Skip to content

Commit 6e1102d

Browse files
authored
Support Expression Restrictions (#348)
* Support expression restrictions * fix missing end
1 parent 20c1162 commit 6e1102d

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

docs/src/manual/expression.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ add_operators_to_jump
5454
## Expression Methods
5555
```@docs
5656
parameter_refs(::Union{JuMP.GenericAffExpr, JuMP.GenericQuadExpr, JuMP.NonlinearExpr})
57+
restrict(::JuMP.AbstractJuMPScalar)
5758
map_expression
5859
map_expression_to_ast
5960
```

src/expressions.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,70 @@ function map_expression_to_ast(
812812
return ex
813813
end
814814

815+
################################################################################
816+
# EXPRESSION RESTICTIONS
817+
################################################################################
818+
"""
819+
restrict(expr::JuMP.AbstractJuMPScalar, supps...)::JuMP.AbstractJuMPScalar
820+
821+
Restrict an infinite expression `expr` to be enforced over infinite parameter
822+
supports `supps`. This is limited to expressions only contain infinite variables
823+
with the same kind of infinite parameter dependencies. Note that more conveniently
824+
the expression can be treated as a function for the syntax `expr(supps...)`.
825+
826+
**Example**
827+
```julia-repl
828+
julia> ex = @expression(model, 3y - 2)
829+
3 y(t) - 2
830+
831+
julia> restrict(ex, 0)
832+
3 y(0) - 2
833+
834+
julia> ex(0)
835+
3 y(0) - 2
836+
```
837+
"""
838+
function restrict(expr::JuMP.AbstractJuMPScalar, supps...)
839+
# check to make sure all variables depend on the same infinite parameters
840+
pref_tuples = Set()
841+
_interrogate_variables(expr) do v
842+
if v.index_type <: InfiniteParameterIndex
843+
error("Restrictions on expressions with infinite parameters are not supported.")
844+
elseif !(v.index_type <: Union{FiniteVariableIndex, PointVariableIndex, FiniteParameterIndex})
845+
push!(pref_tuples, raw_parameter_refs(v))
846+
end
847+
end
848+
if length(pref_tuples) > 1
849+
error("Unable to restrict expression `$expr` with supports `$supps`. " *
850+
"Not all the variables use the same infinite parameters in the " *
851+
"same format.")
852+
end
853+
# restrict the expression using supps and return
854+
return map_expression(expr) do v
855+
if isempty(_object_numbers(v))
856+
return v
857+
else
858+
return restrict(v, supps...)
859+
end
860+
end
861+
end
862+
863+
## Make expressions callable for restrictions
864+
# AffExprs
865+
function (aff::JuMP.GenericAffExpr{Float64, GeneralVariableRef})(supps...)
866+
return restrict(aff, supps...)
867+
end
868+
869+
# QuadExprs
870+
function (quad::JuMP.GenericQuadExpr{Float64, GeneralVariableRef})(supps...)
871+
return restrict(quad, supps...)
872+
end
873+
874+
# NonlinearExprs
875+
function (nl::JuMP.GenericNonlinearExpr{GeneralVariableRef})(supps...)
876+
return restrict(nl, supps...)
877+
end
878+
815879
################################################################################
816880
# COEFFICIENT METHODS
817881
################################################################################

test/expressions.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,34 @@ end
702702
end
703703
end
704704

705+
# Test restrictions
706+
@testset "restrict" begin
707+
# setup model
708+
m = InfiniteModel()
709+
@infinite_parameter(m, t in [0, 1])
710+
@infinite_parameter(m, x in [-1, 1])
711+
@variable(m, y, Infinite(t, x))
712+
@variable(m, q, Infinite(x, t))
713+
@variable(m, w, Infinite(t))
714+
@variable(m, z)
715+
# test AffExpr
716+
@testset "AffExpr" begin
717+
@test (2z + y + 42)(0, -1) == 2z + y(0, -1) + 42
718+
@test (2z + y + 42)(0, x) == 2z + y(0, x) + 42
719+
@test_throws ErrorException (y + q)(0, 0)
720+
@test_throws ErrorException (y + t)(0, x)
721+
end
722+
# test QuadExpr
723+
@testset "QuadExpr" begin
724+
@test (z^2 + 3y - 2)(0, -1) == z^2 + 3y(0, -1) - 2
725+
@test (w^2 - 2)(0) == w(0)^2 - 2
726+
end
727+
# test GenericNonlinearExpr
728+
@testset "GenericNonlinearExpr" begin
729+
@test isequal_canonical((sin(y) * z)(t, -1), sin(y(t, -1)) * z)
730+
end
731+
end
732+
705733
# Test _set_variable_coefficient!
706734
@testset "_set_variable_coefficient!" begin
707735
# initialize model and references

0 commit comments

Comments
 (0)