@@ -379,34 +379,156 @@ julia> f
379379## Utilities.MatrixOfConstraints
380380
381381The constraints of [ ` Utilities.Model ` ] ( @ref ) are stored as a vector of tuples
382- of function and set in a ` Utilities.VectorOfConstraints ` . Other representations
383- can be used by parameterizing the type [ ` Utilities.GenericModel ` ] ( @ref )
384- (resp. [ ` Utilities.GenericOptimizer ` ] ( @ref ) ). For instance, if all
385- non-` VariableIndex ` constraints are affine, the coefficients of all the
386- constraints can be stored in a single sparse matrix using
387- [ ` Utilities.MatrixOfConstraints ` ] ( @ref ) . The constraints storage can even be
388- customized up to a point where it exactly matches the storage of the solver of
389- interest, in which case [ ` copy_to ` ] ( @ref ) can be implemented for the solver by
390- calling [ ` copy_to ` ] ( @ref ) to this custom model.
391-
392- For instance, [ Clp] ( https://github.com/jump-dev/Clp.jl ) defines the following
382+ of function and set in a [ ` Utilities.VectorOfConstraints ` ] ( @ref ) .
383+
384+ Other representations can be used by parameterizing the type
385+ [ ` Utilities.GenericModel ` ] ( @ref ) (resp. [ ` Utilities.GenericOptimizer ` ] ( @ref ) ).
386+
387+ For example, if all non-` VariableIndex ` constraints are affine, the coefficients
388+ of all the constraints can be stored in a single sparse matrix using
389+ [ ` Utilities.MatrixOfConstraints ` ] ( @ref ) .
390+
391+ The constraints storage can even be customized up to a point where it exactly
392+ matches the storage of the solver of interest, in which case [ ` copy_to ` ] ( @ref )
393+ can be implemented for the solver by calling [ ` copy_to ` ] ( @ref ) to this custom
394+ model.
395+
396+ For example, [ Clp.jl] ( https://github.com/jump-dev/Clp.jl ) defines the following
393397model:
394- ``` julia
395- MOI. Utilities. @product_of_scalar_sets (LP, MOI. EqualTo{T}, MOI. LessThan{T}, MOI. GreaterThan{T})
396- const Model = MOI. Utilities. GenericModel{
397- Float64,
398- MOI. Utilities. MatrixOfConstraints{
399- Float64,
400- MOI. Utilities. MutableSparseMatrixCSC{Float64,Cint,MOI. Utilities. ZeroBasedIndexing},
401- MOI. Utilities. Hyperrectangle{Float64},
402- LP{Float64},
403- },
404- }
398+ ``` jldoctest matrixofconstraints
399+ julia> MOI.Utilities.@product_of_sets(
400+ SupportedSets,
401+ MOI.EqualTo{T},
402+ MOI.LessThan{T},
403+ MOI.GreaterThan{T},
404+ MOI.Interval{T},
405+ );
406+
407+ julia> const OptimizerCache = MOI.Utilities.GenericModel{
408+ Float64,
409+ MOI.Utilities.ObjectiveContainer{Float64},
410+ MOI.Utilities.VariablesContainer{Float64},
411+ MOI.Utilities.MatrixOfConstraints{
412+ Float64,
413+ MOI.Utilities.MutableSparseMatrixCSC{
414+ # The data type of the coefficients
415+ Float64,
416+ # The data type of the variable indices
417+ Cint,
418+ # Can also be MOI.Utilities.OneBasedIndexing
419+ MOI.Utilities.ZeroBasedIndexing,
420+ },
421+ MOI.Utilities.Hyperrectangle{Float64},
422+ SupportedSets{Float64},
423+ },
424+ };
425+ ```
426+ Given the input model:
427+ ``` jldoctest matrixofconstraints
428+ julia> src = MOI.Utilities.Model{Float64}();
429+
430+ julia> MOI.Utilities.loadfromstring!(
431+ src,
432+ """
433+ variables: x, y, z
434+ maxobjective: x + 2.0 * y + -3.1 * z
435+ x + y <= 1.0
436+ 2.0 * y >= 3.0
437+ -4.0 * x + z == 5.0
438+ x in Interval(0.0, 1.0)
439+ y <= 10.0
440+ z == 5.0
441+ """,
442+ )
405443```
406444
407- The [ ` copy_to ` ] ( @ref ) operation can now be implemented as follows:
445+ We can construct a new cached model and copy ` src ` to it:
446+ ``` jldoctest matrixofconstraints
447+ julia> dest = OptimizerCache();
448+
449+ julia> index_map = MOI.copy_to(dest, src);
450+ ```
451+
452+ From ` dest ` , we can access the ` A ` matrix in sparse matrix form:
453+ ``` jldoctest matrixofconstraints
454+ julia> A = dest.constraints.coefficients;
455+
456+ julia> A.n
457+ 3
458+
459+ julia> A.m
460+ 3
461+
462+ julia> A.colptr
463+ 4-element Vector{Int32}:
464+ 0
465+ 1
466+ 3
467+ 5
468+
469+ julia> A.rowval
470+ 5-element Vector{Int32}:
471+ 0
472+ 1
473+ 2
474+ 0
475+ 1
476+
477+ julia> A.nzval
478+ 5-element Vector{Float64}:
479+ 1.0
480+ 1.0
481+ 2.0
482+ -4.0
483+ 1.0
484+ ```
485+ The lower and upper row bounds:
486+ ``` jldoctest matrixofconstraints
487+ julia> row_bounds = dest.constraints.constants;
488+
489+ julia> row_bounds.lower
490+ 3-element Vector{Float64}:
491+ 5.0
492+ -Inf
493+ 3.0
494+
495+ julia> row_bounds.upper
496+ 3-element Vector{Float64}:
497+ 5.0
498+ 1.0
499+ Inf
500+ ```
501+ The lower and upper variable bounds:
502+ ``` jldoctest matrixofconstraints
503+ julia> dest.variables.lower
504+ 3-element Vector{Float64}:
505+ 5.0
506+ -Inf
507+ 0.0
508+
509+ julia> dest.variables.upper
510+ 3-element Vector{Float64}:
511+ 5.0
512+ 10.0
513+ 1.0
514+ ```
515+ Because of larger variations between solvers, the objective can be queried using
516+ the standard MOI methods:
517+ ``` jldoctest matrixofconstraints
518+ julia> MOI.get(dest, MOI.ObjectiveSense())
519+ MAX_SENSE::OptimizationSense = 1
520+
521+ julia> F = MOI.get(dest, MOI.ObjectiveFunctionType())
522+ MathOptInterface.ScalarAffineFunction{Float64}
523+
524+ julia> F = MOI.get(dest, MOI.ObjectiveFunction{F}())
525+ 0.0 + 1.0 MOI.VariableIndex(3) + 2.0 MOI.VariableIndex(2) - 3.1 MOI.VariableIndex(1)
526+ ```
527+
528+ Thus, Clp.jl implements [ ` copy_to ` ] ( @ref ) methods similar to the following:
408529``` julia
409- function _copy_to (dest:: Optimizer , src:: Model )
530+ # This method copies from the cache to the `Clp.Optimizer` object.
531+ function MOI. copy_to (dest:: Optimizer , src:: OptimizerCache )
410532 @assert MOI. is_empty (dest)
411533 A = src. constraints. coefficients
412534 row_bounds = src. constraints. constants
@@ -423,35 +545,36 @@ function _copy_to(dest::Optimizer, src::Model)
423545 row_bounds. lower,
424546 row_bounds. upper,
425547 )
426- # Set objective sense and constant (omitted)
427- return
428- end
429-
430- function MOI. copy_to (dest:: Optimizer , src:: Model )
431- _copy_to (dest, src)
432548 return MOI. Utilities. identity_index_map (src)
433549end
434550
435- function MOI . copy_to (
436- dest :: Optimizer ,
437- src:: MOI.Utilities.UniversalFallback{Model} ,
438- )
439- # Copy attributes from ` src` to `dest` and error in case any unsupported
440- # constraints or attributes are set in `UniversalFallback`.
441- return MOI . copy_to (dest, src . model)
551+ # This method copies from an arbitrary model to the optimizer, by the
552+ # intermediate `OptimizerCache` representation.
553+ function MOI . copy_to (dest :: Optimizer , src:: MOI.ModelLike )
554+ cache = OptimizerCache ( )
555+ index_map = MOI . copy_to (cache, src)
556+ MOI . copy_to (dest, cache)
557+ return index_map
442558end
443559
560+ # This is a special method that gets called in some cases when `OptimizerCache`
561+ # is used as the backing data structure in a `MOI.Utilities.CachingOptimizer`.
562+ # It is needed for performance, but not correctness.
444563function MOI. copy_to (
445564 dest:: Optimizer ,
446- src:: MOI.ModelLike ,
565+ src:: MOI.Utilities.UniversalFallback{OptimizerCache} ,
447566)
448- model = Model ()
449- index_map = MOI. copy_to (model, src)
450- _copy_to (dest, model)
451- return index_map
567+ MOI. Utilities. throw_unsupported (src)
568+ return MOI. copy_to (dest, src. model)
452569end
453570```
454571
572+ !!! tip
573+ For other examples of [ ` Utilities.MatrixOfConstraints ` ] ( @ref ) , see:
574+ * [ Cbc.jl] ( https://github.com/jump-dev/Cbc.jl )
575+ * [ ECOS.jl] ( https://github.com/jump-dev/ECOS.jl )
576+ * [ SCS.jl] ( https://github.com/jump-dev/SCS.jl )
577+
455578## ModelFilter
456579
457580Utilities provides [ ` Utilities.ModelFilter ` ] ( @ref ) as a useful tool to copy a
0 commit comments