@@ -379,34 +379,156 @@ julia> f
379
379
## Utilities.MatrixOfConstraints
380
380
381
381
The 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
393
397
model:
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
+ )
405
443
```
406
444
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:
408
529
``` 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 )
410
532
@assert MOI. is_empty (dest)
411
533
A = src. constraints. coefficients
412
534
row_bounds = src. constraints. constants
@@ -423,35 +545,36 @@ function _copy_to(dest::Optimizer, src::Model)
423
545
row_bounds. lower,
424
546
row_bounds. upper,
425
547
)
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)
432
548
return MOI. Utilities. identity_index_map (src)
433
549
end
434
550
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
442
558
end
443
559
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.
444
563
function MOI. copy_to (
445
564
dest:: Optimizer ,
446
- src:: MOI.ModelLike ,
565
+ src:: MOI.Utilities.UniversalFallback{OptimizerCache} ,
447
566
)
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)
452
569
end
453
570
```
454
571
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
+
455
578
## ModelFilter
456
579
457
580
Utilities provides [ ` Utilities.ModelFilter ` ] ( @ref ) as a useful tool to copy a
0 commit comments