diff --git a/benchmark/alternating_minimization.jl b/benchmark/alternating_minimization.jl index b69645c65..6411ec124 100644 --- a/benchmark/alternating_minimization.jl +++ b/benchmark/alternating_minimization.jl @@ -22,11 +22,8 @@ function alternating_minimization(f, A, M, Y_init, k, MAX_ITERS) X = Variable(m, k) Y = Variable(k, n) - objective = ( - norm(vec(M .* A) - vec(M .* (X * Y)), 2) + - γ1 * norm(vec(X), 2) + - γ2 * norm(vec(Y), 1) - ) + objective = + (norm(M .* A - M .* (X * Y), 2) + γ1 * norm(X, 2) + γ2 * norm(Y, 1)) constraints = [X * Y >= ϵ] diff --git a/docs/examples_literate/general_examples/basic_usage.jl b/docs/examples_literate/general_examples/basic_usage.jl index 87f8078ef..fc8f9fad6 100644 --- a/docs/examples_literate/general_examples/basic_usage.jl +++ b/docs/examples_literate/general_examples/basic_usage.jl @@ -47,7 +47,7 @@ println(evaluate(x[1] + x[4] - x[2])) X = Variable(2, 2) y = Variable() ## X is a 2 x 2 variable, and y is scalar. X' + y promotes y to a 2 x 2 variable before adding them -p = minimize(norm(vec(X)) + y, 2 * X <= 1, X' + y >= 1, X >= 0, y >= 0) +p = minimize(norm(X) + y, 2 * X <= 1, X' + y >= 1, X >= 0, y >= 0) solve!(p, SCS.Optimizer; silent_solver = true) println(round.(evaluate(X), digits = 2)) println(evaluate(y)) diff --git a/docs/examples_literate/supplemental_material/paper_examples.jl b/docs/examples_literate/supplemental_material/paper_examples.jl index 030c88548..b6eb6c512 100644 --- a/docs/examples_literate/supplemental_material/paper_examples.jl +++ b/docs/examples_literate/supplemental_material/paper_examples.jl @@ -35,7 +35,7 @@ X = Variable(m, n); A = randn(p, m); b = randn(p, n); @time begin - p = minimize(norm(vec(X)), A * X == b) + p = minimize(norm(X), A * X == b) end @time solve!(p, ECOS.Optimizer; silent_solver = true) @@ -52,6 +52,6 @@ n = 3 A = randn(n, n); #@time begin X = Variable(n, n); -p = minimize(norm(vec(X' - A)), X[1, 1] == 1); +p = minimize(norm(X' - A), X[1, 1] == 1); solve!(p, ECOS.Optimizer; silent_solver = true) #end diff --git a/docs/src/release_notes.md b/docs/src/release_notes.md index 1903b666f..cf33f462e 100644 --- a/docs/src/release_notes.md +++ b/docs/src/release_notes.md @@ -18,6 +18,7 @@ Other changes: * [Type piracy](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy) of `imag` and `real` has been removed. This should not affect use of Convex. Unfortunately, piracy of `hcat`, `vcat`, and `hvcat` still remains. * `sumlargesteigs` now enforces that it's argument is hermitian. * Bugfix: `dot` now correctly complex-conjugates its first argument +* `norm` on `AbstractExpr` objects now supports matrices (treating them like vectors), matching Base's behavior. ## v0.15.4 (October 24, 2023) diff --git a/src/atoms/second_order_cone/norm.jl b/src/atoms/second_order_cone/norm.jl index cb1d31444..0c1f87245 100755 --- a/src/atoms/second_order_cone/norm.jl +++ b/src/atoms/second_order_cone/norm.jl @@ -8,7 +8,8 @@ norm_fro(x::AbstractExpr) = norm2(vec(x)) """ norm(x::AbstractExpr, p::Real=2) -Computes the `p`-norm `‖x‖ₚ = (∑ᵢ |xᵢ|^p)^(1/p)` of a vector expression `x`. +Computes the `p`-norm `‖x‖ₚ = (∑ᵢ |xᵢ|^p)^(1/p)` of a vector expression `x`. Matrices +are vectorized (i.e. `norm(x)` is the same as `norm(vec(x))`.) This function uses specialized methods for `p=1, 2, Inf`. For `p > 1` otherwise, this function uses the procedure documented at @@ -16,31 +17,22 @@ this function uses the procedure documented at based on the paper "Second-order cone programming" by F. Alizadeh and D. Goldfarb, Mathematical Programming, Series B, 95:3-51, 2001. -!!! warning - For versions of Convex.jl prior to v0.14.0, `norm` on a matrix expression returned - the operator norm ([`opnorm`](@ref)), which matches Julia v0.6 behavior. This functionality - was deprecated since Convex.jl v0.8.0, and has been removed. In the future, - `norm(x, p)` will return `‖vec(x)‖ₚ`, matching the behavior of [`norm`](@ref) - for numeric matrices. """ function LinearAlgebra.norm(x::AbstractExpr, p::Real = 2) - if length(size(x)) <= 1 || minimum(size(x)) == 1 - # x is a vector - if p == 1 - return norm_1(x) - elseif p == 2 - return norm2(x) - elseif p == Inf - return norm_inf(x) - elseif p > 1 - # TODO: allow tolerance in the rationalize step - return rationalnorm(x, rationalize(Int, float(p))) - else - error("vector p-norms not defined for p < 1") - end + if size(x, 2) > 1 + x = vec(x) + end + # x is a vector + if p == 1 + return norm_1(x) + elseif p == 2 + return norm2(x) + elseif p == Inf + return norm_inf(x) + elseif p > 1 + # TODO: allow tolerance in the rationalize step + return rationalnorm(x, rationalize(Int, float(p))) else - error( - "In Convex.jl v0.13 and below, `norm(x, p)` meant `opnorm(x, p)` (but was deprecated since v0.8.0). In the future, `norm(x,p)` for matrices will be equivalent to `norm(vec(x),p)`. This is currently an error to ensure you update your code!", - ) + error("vector p-norms not defined for p < 1") end end diff --git a/src/problem_depot/problems/socp.jl b/src/problem_depot/problems/socp.jl index 3b7418f5d..775b8afc3 100644 --- a/src/problem_depot/problems/socp.jl +++ b/src/problem_depot/problems/socp.jl @@ -88,7 +88,7 @@ end ) where {T,test} m = Variable(4, 5) c = [m[3, 3] == 4, m >= 1] - p = minimize(norm(vec(m), 2), c; numeric_type = T) + p = minimize(norm(m, 2), c; numeric_type = T) if test @test problem_vexity(p) == ConvexVexity() @@ -96,7 +96,7 @@ end handle_problem!(p) if test @test p.optval ≈ sqrt(35) atol = atol rtol = rtol - @test evaluate(norm(vec(m), 2)) ≈ sqrt(35) atol = atol rtol = rtol + @test evaluate(norm(m, 2)) ≈ sqrt(35) atol = atol rtol = rtol @test p.constraints[1].dual ≈ 0.6761 atol = atol rtol = rtol dual = 0.1690 .* ones(4, 5) dual[3, 3] = 0 @@ -542,16 +542,11 @@ end @test evaluate(opnorm(x, Inf)) ≈ opnorm(A, Inf) atol = atol rtol = rtol end # Vector norm - # TODO: Once the deprecation for norm on matrices is removed, remove the `vec` calls if test - @test evaluate(norm(vec(x), 1)) ≈ norm(vec(A), 1) atol = atol rtol = - rtol - @test evaluate(norm(vec(x), 2)) ≈ norm(vec(A), 2) atol = atol rtol = - rtol - @test evaluate(norm(vec(x), 7)) ≈ norm(vec(A), 7) atol = atol rtol = - rtol - @test evaluate(norm(vec(x), Inf)) ≈ norm(vec(A), Inf) atol = atol rtol = - rtol + @test evaluate(norm(x, 1)) ≈ norm(vec(A), 1) atol = atol rtol = rtol + @test evaluate(norm(x, 2)) ≈ norm(vec(A), 2) atol = atol rtol = rtol + @test evaluate(norm(x, 7)) ≈ norm(vec(A), 7) atol = atol rtol = rtol + @test evaluate(norm(x, Inf)) ≈ norm(vec(A), Inf) atol = atol rtol = rtol end end