From f37df875a24da1ad94e05b492e907bf383252fee Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 25 Sep 2026 14:51:29 +1200 Subject: [PATCH 1/2] Add MathOptLazy.NumberOfConstraintsActive --- src/MathOptLazy.jl | 25 +++++++++++++++++++++++++ test/runtests.jl | 8 ++++++++ 2 files changed, 33 insertions(+) diff --git a/src/MathOptLazy.jl b/src/MathOptLazy.jl index ca03e1e..0fb78a3 100644 --- a/src/MathOptLazy.jl +++ b/src/MathOptLazy.jl @@ -631,6 +631,31 @@ MOI.get(model::Optimizer, ::MOI.SimplexIterations) = model.simplex_iterations MOI.get(model::Optimizer, ::MOI.SolveTimeSec) = model.solve_time_sec +### MathOptLazy.NumberOfConstraintsActive + +""" + NumberOfConstraintsActive{F,LazyScalarSet{S}}() where { + F<:MOI.AbstractScalarFunction, + S<:MOI.AbstractScalarSet, + } + +Return a count of the number of constraints that are active in the subproblem. +""" +struct NumberOfConstraintsActive{ + F<:MOI.AbstractScalarFunction, + S<:LazyScalarSet{<:MOI.AbstractScalarSet}, +} <: MOI.AbstractModelAttribute +end + +MOI.is_set_by_optimize(::NumberOfConstraintsActive) = true + +function MOI.get( + model::Optimizer, + ::NumberOfConstraintsActive{F,LazyScalarSet{S}}, +) where {F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet} + return count(==(_kLAZY_CONSTRAINT_ACTIVE), _data(model, F, S).status) +end + ### MOI.optimize! function _try_get(model::Optimizer, attr::MOI.AbstractModelAttribute, default) diff --git a/test/runtests.jl b/test/runtests.jl index 6e45b69..5dc46ff 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -43,6 +43,9 @@ function test_jump_cached_knapsack() @test termination_status(model) == OPTIMAL @test primal_status(model) == FEASIBLE_POINT @test all(<=(1 + 1e-6), value(x)) + F = MOI.ScalarAffineFunction{Float64} + S = MathOptLazy.LazyScalarSet{MOI.LessThan{Float64}} + @test get_attribute(model, MathOptLazy.NumberOfConstraintsActive{F,S}()) > 0 return end @@ -54,10 +57,15 @@ function test_jump_direct_knapsack() @constraint(model, [i in 1:N], x[i] <= 1, MathOptLazy.Lazy()) @constraint(model, sum(abs(cos(i)) * x[i] for i in 1:N) <= 0.1 * N) @objective(model, Max, sum(abs(sin(i)) * x[i] for i in 1:N)) + F = MOI.ScalarAffineFunction{Float64} + S = MathOptLazy.LazyScalarSet{MOI.LessThan{Float64}} + attr = MathOptLazy.NumberOfConstraintsActive{F,S}() + @test MOI.get(backend(model), attr) == 0 optimize!(model) @test termination_status(model) == OPTIMAL @test primal_status(model) == FEASIBLE_POINT @test all(<=(1 + 1e-6), value(x)) + @test get_attribute(model, attr) > 0 return end From e83a2b13bd264fa26e9d9453d6aa327eedfda7cd Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 25 Sep 2026 16:37:49 +1200 Subject: [PATCH 2/2] Update MathOptLazy.jl --- src/MathOptLazy.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/MathOptLazy.jl b/src/MathOptLazy.jl index 0fb78a3..8964b4d 100644 --- a/src/MathOptLazy.jl +++ b/src/MathOptLazy.jl @@ -644,8 +644,7 @@ Return a count of the number of constraints that are active in the subproblem. struct NumberOfConstraintsActive{ F<:MOI.AbstractScalarFunction, S<:LazyScalarSet{<:MOI.AbstractScalarSet}, -} <: MOI.AbstractModelAttribute -end +} <: MOI.AbstractModelAttribute end MOI.is_set_by_optimize(::NumberOfConstraintsActive) = true