Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,11 @@
con::BridgeableConstraint,
name::String = "",
)
# Like the generic `add_constraint`, convert to the value type of the model.
# This is needed for constraints that reach this method without going through
# the `model_convert` call of the `@constraint` macro, e.g. constraints built

Check failure on line 752 in src/constraints.jl

View workflow job for this annotation

GitHub Actions / build

[vale] reported by reviewdog 🐶 [Google.Latin] Use 'for example' instead of 'e.g.'. Raw Output: {"message": "[Google.Latin] Use 'for example' instead of 'e.g.'.", "location": {"path": "src/constraints.jl", "range": {"start": {"line": 752, "column": 60}}}, "severity": "ERROR"}
# in `add_constraint` by an extension that delays their construction.
con = model_convert(model, con)
add_bridge(model, con.bridge_type; coefficient_type = con.coefficient_type)
return add_constraint(model, con.constraint, name)
end
Expand Down
10 changes: 9 additions & 1 deletion src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -323,10 +323,18 @@
end

function model_convert(model::AbstractModel, con::BridgeableConstraint)
# The bridge `coefficient_type` is set by `build_constraint` which does not
# have access to the model. We convert it to the value type of the model
# (keeping the same real/complex flavor) just like we convert the
# coefficients of the function. This is needed so that, e.g., the bridges

Check failure on line 329 in src/macros.jl

View workflow job for this annotation

GitHub Actions / build

[vale] reported by reviewdog 🐶 [Google.Latin] Use 'for example' instead of 'e.g.,'. Raw Output: {"message": "[Google.Latin] Use 'for example' instead of 'e.g.,'.", "location": {"path": "src/macros.jl", "range": {"start": {"line": 329, "column": 61}}}, "severity": "ERROR"}
# registered for a `GenericModel{T}` with `T != Float64` use `T`.
return BridgeableConstraint(
model_convert(model, con.constraint),
con.bridge_type;
con.coefficient_type,
coefficient_type = _complex_convert_type(
value_type(typeof(model)),
con.coefficient_type,
),
)
end

Expand Down
54 changes: 53 additions & 1 deletion test/test_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,59 @@
model = Model()
@variable(model, x)
@constraint(model, x in BridgeMe{Int,Nonnegative}(Nonnegative()))
@test NonnegativeBridge{Int} in model.bridge_types
# `model_convert` normalizes the bridge coefficient type to the value type of
# the model (`Float64`), even though `BridgeMe` requested `Int`.
@test NonnegativeBridge{Float64} in model.bridge_types
@test !(NonnegativeBridge{Int} in model.bridge_types)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@test !(NonnegativeBridge{Int} in model.bridge_types)
@test !(NonnegativeBridge{Int} in model.bridge_types)
return

end

function test_model_convert_bridgeable_coefficient_type()
model = GenericModel{BigFloat}()
@variable(model, x)
constraint = ScalarConstraint(x, Nonnegative())
# A real coefficient type is converted to the value type of the model.
con = BridgeableConstraint(
constraint,
NonnegativeBridge;
coefficient_type = Int,
)
@test model_convert(model, con).coefficient_type == BigFloat
# A complex coefficient type keeps its complex flavor.
con = BridgeableConstraint(
constraint,
NonnegativeBridge;
coefficient_type = Complex{Int},
)
@test model_convert(model, con).coefficient_type == Complex{BigFloat}
return
end

function test_macro_bridgeable_generic_value_type()
model = GenericModel{BigFloat}()
@variable(model, x)
@constraint(model, x in BridgeMe{Int,Nonnegative}(Nonnegative()))
@test NonnegativeBridge{BigFloat} in model.bridge_types
@test !(NonnegativeBridge{Int} in model.bridge_types)
return
end

function test_add_constraint_bridgeable_model_convert()
# `add_constraint` applies `model_convert`, so a `BridgeableConstraint` added
# directly (not via the `@constraint` macro, e.g. by an extension that delays

Check failure on line 477 in test/test_model.jl

View workflow job for this annotation

GitHub Actions / build

[vale] reported by reviewdog 🐶 [Google.Latin] Use 'for example' instead of 'e.g.'. Raw Output: {"message": "[Google.Latin] Use 'for example' instead of 'e.g.'.", "location": {"path": "test/test_model.jl", "range": {"start": {"line": 477, "column": 50}}}, "severity": "ERROR"}
# the construction of the constraint) also gets its coefficient type
# converted to the value type of the model.
model = GenericModel{BigFloat}()
@variable(model, x)
constraint = ScalarConstraint(x, Nonnegative())
bc = BridgeableConstraint(
constraint,
NonnegativeBridge;
coefficient_type = Int,
)
add_constraint(model, bc)
@test NonnegativeBridge{BigFloat} in model.bridge_types
@test !(NonnegativeBridge{Int} in model.bridge_types)
return
end

function test_bridges_add_bridgeable_con_set_optimizer()
Expand Down
Loading