passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,1893 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
# sage.doctest: needs sage.geometry.polyhedron
|
|
3
|
+
r"""
|
|
4
|
+
Generic Backend for LP solvers
|
|
5
|
+
|
|
6
|
+
This class only lists the methods that should be defined by any
|
|
7
|
+
interface with a LP Solver. All these methods immediately raise
|
|
8
|
+
:exc:`NotImplementedError` exceptions when called, and are obviously
|
|
9
|
+
meant to be replaced by the solver-specific method. This file can also
|
|
10
|
+
be used as a template to create a new interface : one would only need
|
|
11
|
+
to replace the occurrences of ``"Nonexistent_LP_solver"`` by the
|
|
12
|
+
solver's name, and replace ``GenericBackend`` by
|
|
13
|
+
``SolverName(GenericBackend)`` so that the new solver extends this
|
|
14
|
+
class.
|
|
15
|
+
|
|
16
|
+
AUTHORS:
|
|
17
|
+
|
|
18
|
+
- Nathann Cohen (2010-10) : initial implementation
|
|
19
|
+
- Risan (2012-02) : extension for PPL backend
|
|
20
|
+
- Ingolfur Edvardsson (2014-06): extension for CVXOPT backend
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
#*****************************************************************************
|
|
24
|
+
# Copyright (C) 2010 Nathann Cohen <nathann.cohen@gmail.com>
|
|
25
|
+
#
|
|
26
|
+
# This program is free software: you can redistribute it and/or modify
|
|
27
|
+
# it under the terms of the GNU General Public License as published by
|
|
28
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
29
|
+
# (at your option) any later version.
|
|
30
|
+
# http://www.gnu.org/licenses/
|
|
31
|
+
#*****************************************************************************
|
|
32
|
+
|
|
33
|
+
from copy import copy
|
|
34
|
+
|
|
35
|
+
cdef class GenericBackend:
|
|
36
|
+
|
|
37
|
+
cpdef base_ring(self):
|
|
38
|
+
from sage.rings.real_double import RDF
|
|
39
|
+
return RDF
|
|
40
|
+
|
|
41
|
+
cpdef zero(self):
|
|
42
|
+
return self.base_ring()(0)
|
|
43
|
+
|
|
44
|
+
cpdef int add_variable(self, lower_bound=0, upper_bound=None,
|
|
45
|
+
binary=False, continuous=True, integer=False,
|
|
46
|
+
obj=None, name=None) except -1:
|
|
47
|
+
"""
|
|
48
|
+
Add a variable.
|
|
49
|
+
|
|
50
|
+
This amounts to adding a new column to the matrix. By default,
|
|
51
|
+
the variable is both positive and real.
|
|
52
|
+
|
|
53
|
+
INPUT:
|
|
54
|
+
|
|
55
|
+
- ``lower_bound`` -- the lower bound of the variable (default: 0)
|
|
56
|
+
|
|
57
|
+
- ``upper_bound`` -- the upper bound of the variable (default: ``None``)
|
|
58
|
+
|
|
59
|
+
- ``binary`` -- ``True`` if the variable is binary (default: ``False``)
|
|
60
|
+
|
|
61
|
+
- ``continuous`` -- ``True`` if the variable is continuous (default: ``True``)
|
|
62
|
+
|
|
63
|
+
- ``integer`` -- ``True`` if the variable is integral (default: ``False``)
|
|
64
|
+
|
|
65
|
+
- ``obj`` -- (optional) coefficient of this variable in the objective function (default: 0.0)
|
|
66
|
+
|
|
67
|
+
- ``name`` -- an optional name for the newly added variable (default: ``None``)
|
|
68
|
+
|
|
69
|
+
OUTPUT: the index of the newly created variable
|
|
70
|
+
|
|
71
|
+
EXAMPLES::
|
|
72
|
+
|
|
73
|
+
sage: # optional - nonexistent_lp_solver
|
|
74
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
75
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
76
|
+
sage: p.ncols()
|
|
77
|
+
0
|
|
78
|
+
sage: p.add_variable()
|
|
79
|
+
0
|
|
80
|
+
sage: p.ncols()
|
|
81
|
+
1
|
|
82
|
+
sage: p.add_variable(binary=True)
|
|
83
|
+
1
|
|
84
|
+
sage: p.add_variable(lower_bound=-2.0, integer=True)
|
|
85
|
+
2
|
|
86
|
+
sage: p.add_variable(continuous=True, integer=True)
|
|
87
|
+
Traceback (most recent call last):
|
|
88
|
+
...
|
|
89
|
+
ValueError: ...
|
|
90
|
+
sage: p.add_variable(name='x', obj=1.0)
|
|
91
|
+
3
|
|
92
|
+
sage: p.col_name(3)
|
|
93
|
+
'x'
|
|
94
|
+
sage: p.objective_coefficient(3)
|
|
95
|
+
1.0
|
|
96
|
+
"""
|
|
97
|
+
raise NotImplementedError()
|
|
98
|
+
|
|
99
|
+
cpdef int add_variables(self, int n, lower_bound=False, upper_bound=None, binary=False, continuous=True, integer=False, obj=None, names=None) except -1:
|
|
100
|
+
"""
|
|
101
|
+
Add ``n`` variables.
|
|
102
|
+
|
|
103
|
+
This amounts to adding new columns to the matrix. By default,
|
|
104
|
+
the variables are both nonnegative and real.
|
|
105
|
+
|
|
106
|
+
INPUT:
|
|
107
|
+
|
|
108
|
+
- ``n`` -- the number of new variables (must be > 0)
|
|
109
|
+
|
|
110
|
+
- ``lower_bound`` -- the lower bound of the variable (default: 0)
|
|
111
|
+
|
|
112
|
+
- ``upper_bound`` -- the upper bound of the variable (default: ``None``)
|
|
113
|
+
|
|
114
|
+
- ``binary`` -- ``True`` if the variable is binary (default: ``False``)
|
|
115
|
+
|
|
116
|
+
- ``continuous`` -- ``True`` if the variable is binary (default: ``True``)
|
|
117
|
+
|
|
118
|
+
- ``integer`` -- ``True`` if the variable is binary (default: ``False``)
|
|
119
|
+
|
|
120
|
+
- ``obj`` -- coefficient of all variables in the objective function (default: 0.0)
|
|
121
|
+
|
|
122
|
+
- ``names`` -- list of names (default: ``None``)
|
|
123
|
+
|
|
124
|
+
OUTPUT: the index of the variable created last
|
|
125
|
+
|
|
126
|
+
EXAMPLES::
|
|
127
|
+
|
|
128
|
+
sage: # optional - nonexistent_lp_solver
|
|
129
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
130
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
131
|
+
sage: p.ncols()
|
|
132
|
+
0
|
|
133
|
+
sage: p.add_variables(5)
|
|
134
|
+
4
|
|
135
|
+
sage: p.ncols()
|
|
136
|
+
5
|
|
137
|
+
sage: p.add_variables(2, lower_bound=-2.0, integer=True, names=['a','b'])
|
|
138
|
+
6
|
|
139
|
+
|
|
140
|
+
TESTS:
|
|
141
|
+
|
|
142
|
+
Check that arguments are used::
|
|
143
|
+
|
|
144
|
+
sage: # optional - nonexistent_lp_solver
|
|
145
|
+
sage: p.col_bounds(5) # tol 1e-8
|
|
146
|
+
(-2.0, None)
|
|
147
|
+
sage: p.is_variable_integer(5)
|
|
148
|
+
True
|
|
149
|
+
sage: p.col_name(5)
|
|
150
|
+
'a'
|
|
151
|
+
sage: p.objective_coefficient(5) # tol 1e-8
|
|
152
|
+
42.0
|
|
153
|
+
"""
|
|
154
|
+
cdef int i
|
|
155
|
+
cdef int value
|
|
156
|
+
if lower_bound is False:
|
|
157
|
+
lower_bound = self.zero()
|
|
158
|
+
if obj is None:
|
|
159
|
+
obj = self.zero()
|
|
160
|
+
for i in range(n):
|
|
161
|
+
value = self.add_variable(lower_bound=lower_bound,
|
|
162
|
+
upper_bound=upper_bound,
|
|
163
|
+
binary=binary,
|
|
164
|
+
continuous=continuous,
|
|
165
|
+
integer=integer,
|
|
166
|
+
obj=obj,
|
|
167
|
+
name=None if names is None else names[i])
|
|
168
|
+
return value
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def _test_add_variables(cls, tester=None, **options):
|
|
172
|
+
"""
|
|
173
|
+
Run tests on the method :meth:`add_linear_constraints`.
|
|
174
|
+
|
|
175
|
+
TESTS::
|
|
176
|
+
|
|
177
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
178
|
+
sage: p = GenericBackend()
|
|
179
|
+
sage: p._test_add_variables()
|
|
180
|
+
Traceback (most recent call last):
|
|
181
|
+
...
|
|
182
|
+
NotImplementedError
|
|
183
|
+
|
|
184
|
+
Flush any stray output -- see :issue:`28622`::
|
|
185
|
+
|
|
186
|
+
sage: sys.stdout.flush()
|
|
187
|
+
...
|
|
188
|
+
"""
|
|
189
|
+
p = cls() # fresh instance of the backend
|
|
190
|
+
if tester is None:
|
|
191
|
+
tester = p._tester(**options)
|
|
192
|
+
# Test from CVXOPT interface:
|
|
193
|
+
ncols_added = 5
|
|
194
|
+
ncols_before = p.ncols()
|
|
195
|
+
add_variables_result = p.add_variables(ncols_added)
|
|
196
|
+
ncols_after = p.ncols()
|
|
197
|
+
tester.assertEqual(ncols_after, ncols_before+ncols_added, "Added the wrong number of columns")
|
|
198
|
+
# Test from CVXOPT interface, continued; edited to support InteractiveLPBackend
|
|
199
|
+
ncols_before = p.ncols()
|
|
200
|
+
try:
|
|
201
|
+
col_bounds = (-2.0, None)
|
|
202
|
+
add_variables_result = p.add_variables(2, lower_bound=col_bounds[0], upper_bound=col_bounds[1],
|
|
203
|
+
obj=42.0, names=['a','b'])
|
|
204
|
+
except NotImplementedError:
|
|
205
|
+
# The InteractiveLPBackend does not allow general variable bounds.
|
|
206
|
+
col_bounds = (0.0, None)
|
|
207
|
+
add_variables_result = p.add_variables(2, lower_bound=col_bounds[0], upper_bound=col_bounds[1],
|
|
208
|
+
obj=42.0, names=['a','b'])
|
|
209
|
+
ncols_after = p.ncols()
|
|
210
|
+
tester.assertAlmostEqual(p.col_bounds(ncols_before), col_bounds)
|
|
211
|
+
tester.assertEqual(p.col_name(ncols_before), 'a')
|
|
212
|
+
tester.assertAlmostEqual(p.objective_coefficient(ncols_before), 42.0)
|
|
213
|
+
|
|
214
|
+
cpdef set_variable_type(self, int variable, int vtype):
|
|
215
|
+
"""
|
|
216
|
+
Set the type of a variable.
|
|
217
|
+
|
|
218
|
+
INPUT:
|
|
219
|
+
|
|
220
|
+
- ``variable`` -- integer; the variable's id
|
|
221
|
+
|
|
222
|
+
- ``vtype`` -- integer:
|
|
223
|
+
|
|
224
|
+
* `1` Integer
|
|
225
|
+
* `0` Binary
|
|
226
|
+
* `-1` Continuous
|
|
227
|
+
|
|
228
|
+
EXAMPLES::
|
|
229
|
+
|
|
230
|
+
sage: # optional - nonexistent_lp_solver
|
|
231
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
232
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
233
|
+
sage: p.ncols()
|
|
234
|
+
0
|
|
235
|
+
sage: p.add_variable()
|
|
236
|
+
0
|
|
237
|
+
sage: p.set_variable_type(0,1)
|
|
238
|
+
sage: p.is_variable_integer(0)
|
|
239
|
+
True
|
|
240
|
+
"""
|
|
241
|
+
raise NotImplementedError()
|
|
242
|
+
|
|
243
|
+
cpdef set_sense(self, int sense):
|
|
244
|
+
"""
|
|
245
|
+
Set the direction (maximization/minimization).
|
|
246
|
+
|
|
247
|
+
INPUT:
|
|
248
|
+
|
|
249
|
+
- ``sense`` -- integer:
|
|
250
|
+
|
|
251
|
+
* +1 => Maximization
|
|
252
|
+
* -1 => Minimization
|
|
253
|
+
|
|
254
|
+
EXAMPLES::
|
|
255
|
+
|
|
256
|
+
sage: # optional - nonexistent_lp_solver
|
|
257
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
258
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
259
|
+
sage: p.is_maximization()
|
|
260
|
+
True
|
|
261
|
+
sage: p.set_sense(-1)
|
|
262
|
+
sage: p.is_maximization()
|
|
263
|
+
False
|
|
264
|
+
"""
|
|
265
|
+
raise NotImplementedError()
|
|
266
|
+
|
|
267
|
+
@classmethod
|
|
268
|
+
def _test_sense(cls, tester=None, **options):
|
|
269
|
+
"""
|
|
270
|
+
Run tests on ``set_sense`` and ``is_maximization``.
|
|
271
|
+
|
|
272
|
+
TESTS::
|
|
273
|
+
|
|
274
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
275
|
+
sage: p = GenericBackend()
|
|
276
|
+
sage: p._test_sense() # optional - Nonexistent_LP_solver
|
|
277
|
+
Exception NotImplementedError ...
|
|
278
|
+
"""
|
|
279
|
+
p = cls() # fresh instance of the backend
|
|
280
|
+
if tester is None:
|
|
281
|
+
tester = p._tester(**options)
|
|
282
|
+
tester.assertEqual(p.is_maximization(), True)
|
|
283
|
+
tester.assertIsNone(p.set_sense(-1))
|
|
284
|
+
tester.assertEqual(p.is_maximization(), False)
|
|
285
|
+
tester.assertIsNone(p.set_sense(1))
|
|
286
|
+
tester.assertEqual(p.is_maximization(), True)
|
|
287
|
+
|
|
288
|
+
cpdef objective_coefficient(self, int variable, coeff=None):
|
|
289
|
+
"""
|
|
290
|
+
Set or get the coefficient of a variable in the objective
|
|
291
|
+
function
|
|
292
|
+
|
|
293
|
+
INPUT:
|
|
294
|
+
|
|
295
|
+
- ``variable`` -- integer; the variable's id
|
|
296
|
+
|
|
297
|
+
- ``coeff`` -- double; its coefficient
|
|
298
|
+
|
|
299
|
+
EXAMPLES::
|
|
300
|
+
|
|
301
|
+
sage: # optional - nonexistent_lp_solver
|
|
302
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
303
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
304
|
+
sage: p.add_variable()
|
|
305
|
+
0
|
|
306
|
+
sage: p.objective_coefficient(0)
|
|
307
|
+
0.0
|
|
308
|
+
sage: p.objective_coefficient(0,2)
|
|
309
|
+
sage: p.objective_coefficient(0)
|
|
310
|
+
2.0
|
|
311
|
+
"""
|
|
312
|
+
raise NotImplementedError()
|
|
313
|
+
|
|
314
|
+
cpdef objective_constant_term(self, d=None):
|
|
315
|
+
"""
|
|
316
|
+
Set or get the constant term in the objective function.
|
|
317
|
+
|
|
318
|
+
INPUT:
|
|
319
|
+
|
|
320
|
+
- ``d`` -- double; its coefficient. If ``None`` (default), return the
|
|
321
|
+
current value.
|
|
322
|
+
|
|
323
|
+
EXAMPLES::
|
|
324
|
+
|
|
325
|
+
sage: # optional - nonexistent_lp_solver
|
|
326
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
327
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
328
|
+
sage: p.objective_constant_term()
|
|
329
|
+
0.0
|
|
330
|
+
sage: p.objective_constant_term(42)
|
|
331
|
+
sage: p.objective_constant_term()
|
|
332
|
+
42.0
|
|
333
|
+
"""
|
|
334
|
+
if d is None:
|
|
335
|
+
return self.obj_constant_term
|
|
336
|
+
else:
|
|
337
|
+
self.obj_constant_term = d
|
|
338
|
+
|
|
339
|
+
cpdef set_objective(self, list coeff, d=0.0):
|
|
340
|
+
"""
|
|
341
|
+
Set the objective function.
|
|
342
|
+
|
|
343
|
+
INPUT:
|
|
344
|
+
|
|
345
|
+
- ``coeff`` -- list of real values, whose i-th element is the
|
|
346
|
+
coefficient of the i-th variable in the objective function
|
|
347
|
+
|
|
348
|
+
- ``d`` -- double; the constant term in the linear function (set to `0`
|
|
349
|
+
by default)
|
|
350
|
+
|
|
351
|
+
EXAMPLES::
|
|
352
|
+
|
|
353
|
+
sage: # optional - nonexistent_lp_solver
|
|
354
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
355
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
356
|
+
sage: p.add_variables(5)
|
|
357
|
+
4
|
|
358
|
+
sage: p.set_objective([1, 1, 2, 1, 3])
|
|
359
|
+
sage: [p.objective_coefficient(x) for x in range(5)]
|
|
360
|
+
[1.0, 1.0, 2.0, 1.0, 3.0]
|
|
361
|
+
|
|
362
|
+
Constants in the objective function are respected::
|
|
363
|
+
|
|
364
|
+
sage: # optional - nonexistent_lp_solver
|
|
365
|
+
sage: p = MixedIntegerLinearProgram(solver='Nonexistent_LP_solver')
|
|
366
|
+
sage: x,y = p[0], p[1]
|
|
367
|
+
sage: p.add_constraint(2*x + 3*y, max=6)
|
|
368
|
+
sage: p.add_constraint(3*x + 2*y, max=6)
|
|
369
|
+
sage: p.set_objective(x + y + 7)
|
|
370
|
+
sage: p.set_integer(x); p.set_integer(y)
|
|
371
|
+
sage: p.solve()
|
|
372
|
+
9.0
|
|
373
|
+
"""
|
|
374
|
+
raise NotImplementedError()
|
|
375
|
+
|
|
376
|
+
cpdef set_verbosity(self, int level):
|
|
377
|
+
"""
|
|
378
|
+
Set the log (verbosity) level.
|
|
379
|
+
|
|
380
|
+
INPUT:
|
|
381
|
+
|
|
382
|
+
- ``level`` -- integer; from 0 (no verbosity) to 3
|
|
383
|
+
|
|
384
|
+
EXAMPLES::
|
|
385
|
+
|
|
386
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
387
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver
|
|
388
|
+
sage: p.set_verbosity(2) # optional - Nonexistent_LP_solver
|
|
389
|
+
"""
|
|
390
|
+
raise NotImplementedError()
|
|
391
|
+
|
|
392
|
+
cpdef remove_constraint(self, int i):
|
|
393
|
+
r"""
|
|
394
|
+
Remove a constraint.
|
|
395
|
+
|
|
396
|
+
INPUT:
|
|
397
|
+
|
|
398
|
+
- ``i`` -- index of the constraint to remove
|
|
399
|
+
|
|
400
|
+
EXAMPLES::
|
|
401
|
+
|
|
402
|
+
sage: # optional - nonexistent_lp_solver
|
|
403
|
+
sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver")
|
|
404
|
+
sage: v = p.new_variable(nonnegative=True)
|
|
405
|
+
sage: x,y = v[0], v[1]
|
|
406
|
+
sage: p.add_constraint(2*x + 3*y, max=6)
|
|
407
|
+
sage: p.add_constraint(3*x + 2*y, max=6)
|
|
408
|
+
sage: p.set_objective(x + y + 7)
|
|
409
|
+
sage: p.set_integer(x); p.set_integer(y)
|
|
410
|
+
sage: p.solve()
|
|
411
|
+
9.0
|
|
412
|
+
sage: p.remove_constraint(0)
|
|
413
|
+
sage: p.solve()
|
|
414
|
+
10.0
|
|
415
|
+
sage: p.get_values([x,y])
|
|
416
|
+
[0.0, 3.0]
|
|
417
|
+
"""
|
|
418
|
+
raise NotImplementedError()
|
|
419
|
+
|
|
420
|
+
cpdef remove_constraints(self, constraints):
|
|
421
|
+
r"""
|
|
422
|
+
Remove several constraints.
|
|
423
|
+
|
|
424
|
+
INPUT:
|
|
425
|
+
|
|
426
|
+
- ``constraints`` -- an iterable containing the indices of the rows to remove
|
|
427
|
+
|
|
428
|
+
EXAMPLES::
|
|
429
|
+
|
|
430
|
+
sage: # optional - nonexistent_lp_solver
|
|
431
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
432
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
433
|
+
sage: p.add_variables(2)
|
|
434
|
+
1
|
|
435
|
+
sage: p.add_linear_constraint([(0, 2), (1, 3)], None, 6)
|
|
436
|
+
sage: p.add_linear_constraint([(0, 3), (1, 2)], None, 6)
|
|
437
|
+
sage: p.remove_constraints([0, 1])
|
|
438
|
+
"""
|
|
439
|
+
if isinstance(constraints, int):
|
|
440
|
+
self.remove_constraint(constraints)
|
|
441
|
+
return
|
|
442
|
+
|
|
443
|
+
cdef int last = self.nrows() + 1
|
|
444
|
+
|
|
445
|
+
for c in sorted(constraints, reverse=True):
|
|
446
|
+
if c != last:
|
|
447
|
+
self.remove_constraint(c)
|
|
448
|
+
last = c
|
|
449
|
+
|
|
450
|
+
cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name=None):
|
|
451
|
+
"""
|
|
452
|
+
Add a linear constraint.
|
|
453
|
+
|
|
454
|
+
INPUT:
|
|
455
|
+
|
|
456
|
+
- ``coefficients`` -- an iterable of pairs ``(i, v)``. In each
|
|
457
|
+
pair, ``i`` is a variable index (integer) and ``v`` is a
|
|
458
|
+
value (element of :meth:`base_ring`).
|
|
459
|
+
|
|
460
|
+
- ``lower_bound`` -- element of :meth:`base_ring` or
|
|
461
|
+
``None``; the lower bound
|
|
462
|
+
|
|
463
|
+
- ``upper_bound`` -- element of :meth:`base_ring` or
|
|
464
|
+
``None``; the upper bound
|
|
465
|
+
|
|
466
|
+
- ``name`` -- string or ``None``; optional name for this row
|
|
467
|
+
|
|
468
|
+
EXAMPLES::
|
|
469
|
+
|
|
470
|
+
sage: # optional - nonexistent_lp_solver
|
|
471
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
472
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
473
|
+
sage: p.add_variables(5)
|
|
474
|
+
4
|
|
475
|
+
sage: p.add_linear_constraint( zip(range(5), range(5)), 2.0, 2.0)
|
|
476
|
+
sage: p.row(0)
|
|
477
|
+
([0, 1, 2, 3, 4], [0.0, 1.0, 2.0, 3.0, 4.0])
|
|
478
|
+
sage: p.row_bounds(0)
|
|
479
|
+
(2.0, 2.0)
|
|
480
|
+
sage: p.add_linear_constraint( zip(range(5), range(5)), 1.0, 1.0, name='foo')
|
|
481
|
+
sage: p.row_name(1)
|
|
482
|
+
'foo'
|
|
483
|
+
"""
|
|
484
|
+
raise NotImplementedError('add_linear_constraint')
|
|
485
|
+
|
|
486
|
+
cpdef add_linear_constraint_vector(self, degree, coefficients, lower_bound, upper_bound, name=None):
|
|
487
|
+
"""
|
|
488
|
+
Add a vector-valued linear constraint.
|
|
489
|
+
|
|
490
|
+
.. NOTE::
|
|
491
|
+
|
|
492
|
+
This is the generic implementation, which will split the
|
|
493
|
+
vector-valued constraint into components and add these
|
|
494
|
+
individually. Backends are encouraged to replace it with
|
|
495
|
+
their own optimized implementation.
|
|
496
|
+
|
|
497
|
+
INPUT:
|
|
498
|
+
|
|
499
|
+
- ``degree`` -- integer; the vector degree, that is, the
|
|
500
|
+
number of new scalar constraints
|
|
501
|
+
|
|
502
|
+
- ``coefficients`` -- an iterable of pairs ``(i, v)``. In each
|
|
503
|
+
pair, ``i`` is a variable index (integer) and ``v`` is a
|
|
504
|
+
vector (real and of length ``degree``).
|
|
505
|
+
|
|
506
|
+
- ``lower_bound`` -- either a vector or ``None``; the
|
|
507
|
+
component-wise lower bound
|
|
508
|
+
|
|
509
|
+
- ``upper_bound`` -- either a vector or ``None``; the
|
|
510
|
+
component-wise upper bound
|
|
511
|
+
|
|
512
|
+
- ``name`` -- string or ``None``; an optional name for all new
|
|
513
|
+
rows
|
|
514
|
+
|
|
515
|
+
EXAMPLES::
|
|
516
|
+
|
|
517
|
+
sage: # optional - nonexistent_lp_solver
|
|
518
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
519
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
520
|
+
sage: coeffs = ([0, vector([1, 2])], [1, vector([2, 3])])
|
|
521
|
+
sage: upper = vector([5, 5])
|
|
522
|
+
sage: lower = vector([0, 0])
|
|
523
|
+
sage: p.add_variables(2)
|
|
524
|
+
1
|
|
525
|
+
sage: p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo')
|
|
526
|
+
"""
|
|
527
|
+
for d in range(degree):
|
|
528
|
+
coefficients_d = []
|
|
529
|
+
for i, c in coefficients:
|
|
530
|
+
coefficients_d.append((i, c[d]))
|
|
531
|
+
lower_bound_d = None if lower_bound is None else lower_bound[d]
|
|
532
|
+
upper_bound_d = None if upper_bound is None else upper_bound[d]
|
|
533
|
+
self.add_linear_constraint(coefficients_d, lower_bound_d, upper_bound_d, name=name)
|
|
534
|
+
|
|
535
|
+
@classmethod
|
|
536
|
+
def _test_add_linear_constraint_vector(cls, tester=None, **options):
|
|
537
|
+
"""
|
|
538
|
+
Run tests on the method :meth:`add_linear_constraint_vector`.
|
|
539
|
+
|
|
540
|
+
TESTS::
|
|
541
|
+
|
|
542
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
543
|
+
sage: p = GenericBackend()
|
|
544
|
+
sage: p._test_add_linear_constraint_vector()
|
|
545
|
+
Traceback (most recent call last):
|
|
546
|
+
...
|
|
547
|
+
NotImplementedError
|
|
548
|
+
"""
|
|
549
|
+
p = cls() # fresh instance of the backend
|
|
550
|
+
if tester is None:
|
|
551
|
+
tester = p._tester(**options)
|
|
552
|
+
from sage.modules.free_module_element import vector
|
|
553
|
+
# Ensure there are at least 2 variables
|
|
554
|
+
p.add_variables(2)
|
|
555
|
+
coeffs = ([0, vector([1, 2])], [1, vector([2, 3])])
|
|
556
|
+
upper = vector([5, 5])
|
|
557
|
+
lower = vector([0, 0])
|
|
558
|
+
try:
|
|
559
|
+
p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo')
|
|
560
|
+
except NotImplementedError:
|
|
561
|
+
# Ranged constraints are not supported by InteractiveLPBackend
|
|
562
|
+
lower = None
|
|
563
|
+
p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo')
|
|
564
|
+
# FIXME: Tests here. Careful what we expect regarding ranged constraints with some solvers.
|
|
565
|
+
|
|
566
|
+
cpdef add_col(self, indices, coeffs):
|
|
567
|
+
"""
|
|
568
|
+
Add a column.
|
|
569
|
+
|
|
570
|
+
INPUT:
|
|
571
|
+
|
|
572
|
+
- ``indices`` -- list of integers; this list contains the
|
|
573
|
+
indices of the constraints in which the variable's
|
|
574
|
+
coefficient is nonzero
|
|
575
|
+
|
|
576
|
+
- ``coeffs`` -- list of real values; associates a coefficient
|
|
577
|
+
to the variable in each of the constraints in which it
|
|
578
|
+
appears. Namely, the i-th entry of ``coeffs`` corresponds to
|
|
579
|
+
the coefficient of the variable in the constraint
|
|
580
|
+
represented by the i-th entry in ``indices``.
|
|
581
|
+
|
|
582
|
+
.. NOTE::
|
|
583
|
+
|
|
584
|
+
``indices`` and ``coeffs`` are expected to be of the same
|
|
585
|
+
length.
|
|
586
|
+
|
|
587
|
+
EXAMPLES::
|
|
588
|
+
|
|
589
|
+
sage: # optional - nonexistent_lp_solver
|
|
590
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
591
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
592
|
+
sage: p.ncols()
|
|
593
|
+
0
|
|
594
|
+
sage: p.nrows()
|
|
595
|
+
0
|
|
596
|
+
sage: p.add_linear_constraints(5, 0, None)
|
|
597
|
+
sage: p.add_col(list(range(5)), list(range(5)))
|
|
598
|
+
sage: p.nrows()
|
|
599
|
+
5
|
|
600
|
+
"""
|
|
601
|
+
raise NotImplementedError()
|
|
602
|
+
|
|
603
|
+
@classmethod
|
|
604
|
+
def _test_add_col(cls, tester=None, **options):
|
|
605
|
+
"""
|
|
606
|
+
Run tests on the method :meth:`add_col`.
|
|
607
|
+
|
|
608
|
+
TESTS::
|
|
609
|
+
|
|
610
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
611
|
+
sage: p = GenericBackend()
|
|
612
|
+
sage: p._test_add_col()
|
|
613
|
+
Traceback (most recent call last):
|
|
614
|
+
...
|
|
615
|
+
NotImplementedError: ...
|
|
616
|
+
"""
|
|
617
|
+
p = cls() # fresh instance of the backend
|
|
618
|
+
if tester is None:
|
|
619
|
+
tester = p._tester(**options)
|
|
620
|
+
tester.assertIsNone(p.add_linear_constraints(5, 0, None))
|
|
621
|
+
tester.assertIsNone(p.add_col([0, 1, 2, 3, 4], [0, 1, 2, 3, 4]))
|
|
622
|
+
tester.assertEqual(p.nrows(), 5)
|
|
623
|
+
for 1 <= i <= 4:
|
|
624
|
+
tester.assertEqual(p.row(i), ([0], [i]))
|
|
625
|
+
|
|
626
|
+
cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names=None):
|
|
627
|
+
"""
|
|
628
|
+
Add ``'number`` linear constraints.
|
|
629
|
+
|
|
630
|
+
INPUT:
|
|
631
|
+
|
|
632
|
+
- ``number`` -- integer; the number of constraints to add
|
|
633
|
+
|
|
634
|
+
- ``lower_bound`` -- a lower bound, either a real value or ``None``
|
|
635
|
+
|
|
636
|
+
- ``upper_bound`` -- an upper bound, either a real value or ``None``
|
|
637
|
+
|
|
638
|
+
- ``names`` -- an optional list of names (default: ``None``)
|
|
639
|
+
|
|
640
|
+
EXAMPLES::
|
|
641
|
+
|
|
642
|
+
sage: # optional - nonexistent_lp_solver
|
|
643
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
644
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
645
|
+
sage: p.add_variables(5)
|
|
646
|
+
5
|
|
647
|
+
sage: p.add_linear_constraints(5, None, 2)
|
|
648
|
+
sage: p.row(4)
|
|
649
|
+
([], [])
|
|
650
|
+
sage: p.row_bounds(4)
|
|
651
|
+
(None, 2.0)
|
|
652
|
+
"""
|
|
653
|
+
cdef int i
|
|
654
|
+
for 0<= i<number:
|
|
655
|
+
self.add_linear_constraint([],lower_bound, upper_bound, name = (names[i] if names else None))
|
|
656
|
+
|
|
657
|
+
@classmethod
|
|
658
|
+
def _test_add_linear_constraints(cls, tester=None, **options):
|
|
659
|
+
"""
|
|
660
|
+
Run tests on the method :meth:`add_linear_constraints`.
|
|
661
|
+
|
|
662
|
+
TESTS::
|
|
663
|
+
|
|
664
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
665
|
+
sage: p = GenericBackend()
|
|
666
|
+
sage: p._test_add_linear_constraints()
|
|
667
|
+
Traceback (most recent call last):
|
|
668
|
+
...
|
|
669
|
+
NotImplementedError...
|
|
670
|
+
|
|
671
|
+
Flush any stray output -- see :issue:`28622`::
|
|
672
|
+
|
|
673
|
+
sage: sys.stdout.flush()
|
|
674
|
+
...
|
|
675
|
+
"""
|
|
676
|
+
p = cls() # fresh instance of the backend
|
|
677
|
+
if tester is None:
|
|
678
|
+
tester = p._tester(**options)
|
|
679
|
+
nrows_before = p.nrows()
|
|
680
|
+
nrows_added = 5
|
|
681
|
+
p.add_linear_constraints(nrows_added, None, 2)
|
|
682
|
+
nrows_after = p.nrows()
|
|
683
|
+
# Test correct number of rows
|
|
684
|
+
tester.assertEqual(nrows_after, nrows_before+nrows_added, "Added the wrong number of rows")
|
|
685
|
+
# Test contents of the new rows are correct (sparse zero)
|
|
686
|
+
for i in range(nrows_before, nrows_after):
|
|
687
|
+
tester.assertEqual(p.row(i), ([], []))
|
|
688
|
+
tester.assertEqual(p.row_bounds(i), (None, 2.0))
|
|
689
|
+
# Test from COINBackend.add_linear_constraints:
|
|
690
|
+
tester.assertIsNone(p.add_linear_constraints(2, None, 2, names=['foo', 'bar']))
|
|
691
|
+
tester.assertEqual(p.row_name(6), 'bar')
|
|
692
|
+
# Test that it did not add mysterious new variables:
|
|
693
|
+
tester.assertEqual(p.ncols(), 0)
|
|
694
|
+
|
|
695
|
+
cpdef int solve(self) except -1:
|
|
696
|
+
"""
|
|
697
|
+
Solve the problem.
|
|
698
|
+
|
|
699
|
+
.. NOTE::
|
|
700
|
+
|
|
701
|
+
This method raises ``MIPSolverException`` exceptions when
|
|
702
|
+
the solution cannot be computed for any reason (none
|
|
703
|
+
exists, or the LP solver was not able to find it, etc...)
|
|
704
|
+
|
|
705
|
+
EXAMPLES::
|
|
706
|
+
|
|
707
|
+
sage: # optional - nonexistent_lp_solver
|
|
708
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
709
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
710
|
+
sage: p.add_linear_constraints(5, 0, None)
|
|
711
|
+
sage: p.add_col(list(range(5)), list(range(5)))
|
|
712
|
+
sage: p.solve()
|
|
713
|
+
0
|
|
714
|
+
sage: p.objective_coefficient(0,1)
|
|
715
|
+
sage: p.solve()
|
|
716
|
+
Traceback (most recent call last):
|
|
717
|
+
...
|
|
718
|
+
MIPSolverException: ...
|
|
719
|
+
"""
|
|
720
|
+
raise NotImplementedError()
|
|
721
|
+
|
|
722
|
+
## Any test methods involving calls to 'solve' are set up as class methods,
|
|
723
|
+
## which make a fresh instance of the backend.
|
|
724
|
+
@classmethod
|
|
725
|
+
def _test_solve(cls, tester=None, **options):
|
|
726
|
+
"""
|
|
727
|
+
Trivial test for the solve method.
|
|
728
|
+
|
|
729
|
+
TESTS::
|
|
730
|
+
|
|
731
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
732
|
+
sage: p = GenericBackend()
|
|
733
|
+
sage: p._test_solve()
|
|
734
|
+
Traceback (most recent call last):
|
|
735
|
+
...
|
|
736
|
+
NotImplementedError: ...
|
|
737
|
+
"""
|
|
738
|
+
p = cls() # fresh instance of the backend
|
|
739
|
+
if tester is None:
|
|
740
|
+
tester = p._tester(**options)
|
|
741
|
+
# From doctest of GenericBackend.solve:
|
|
742
|
+
tester.assertIsNone(p.add_linear_constraints(5, 0, None))
|
|
743
|
+
tester.assertIsNone(p.add_col(list(range(5)), list(range(5))))
|
|
744
|
+
tester.assertEqual(p.solve(), 0)
|
|
745
|
+
tester.assertIsNone(p.objective_coefficient(0,1))
|
|
746
|
+
from sage.numerical.mip import MIPSolverException
|
|
747
|
+
#with tester.assertRaisesRegexp(MIPSolverException, "unbounded") as cm: ## --- too specific
|
|
748
|
+
with tester.assertRaises(MIPSolverException) as cm: # unbounded
|
|
749
|
+
p.solve()
|
|
750
|
+
|
|
751
|
+
cpdef get_objective_value(self):
|
|
752
|
+
"""
|
|
753
|
+
Return the value of the objective function.
|
|
754
|
+
|
|
755
|
+
.. NOTE::
|
|
756
|
+
|
|
757
|
+
Behavior is undefined unless ``solve`` has been called before.
|
|
758
|
+
|
|
759
|
+
EXAMPLES::
|
|
760
|
+
|
|
761
|
+
sage: # optional - nonexistent_lp_solver
|
|
762
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
763
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
764
|
+
sage: p.add_variables(2)
|
|
765
|
+
1
|
|
766
|
+
sage: p.add_linear_constraint([(0,1), (1,2)], None, 3)
|
|
767
|
+
sage: p.set_objective([2, 5])
|
|
768
|
+
sage: p.solve()
|
|
769
|
+
0
|
|
770
|
+
sage: p.get_objective_value()
|
|
771
|
+
7.5
|
|
772
|
+
sage: p.get_variable_value(0)
|
|
773
|
+
0.0
|
|
774
|
+
sage: p.get_variable_value(1)
|
|
775
|
+
1.5
|
|
776
|
+
"""
|
|
777
|
+
|
|
778
|
+
raise NotImplementedError()
|
|
779
|
+
|
|
780
|
+
cpdef best_known_objective_bound(self):
|
|
781
|
+
r"""
|
|
782
|
+
Return the value of the currently best known bound.
|
|
783
|
+
|
|
784
|
+
This method returns the current best upper (resp. lower) bound on the
|
|
785
|
+
optimal value of the objective function in a maximization
|
|
786
|
+
(resp. minimization) problem. It is equal to the output of
|
|
787
|
+
:meth:`get_objective_value` if the MILP found an optimal solution, but
|
|
788
|
+
it can differ if it was interrupted manually or after a time limit (cf
|
|
789
|
+
:meth:`solver_parameter`).
|
|
790
|
+
|
|
791
|
+
.. NOTE::
|
|
792
|
+
|
|
793
|
+
Has no meaning unless ``solve`` has been called before.
|
|
794
|
+
|
|
795
|
+
EXAMPLES::
|
|
796
|
+
|
|
797
|
+
sage: # optional - nonexistent_lp_solver
|
|
798
|
+
sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver")
|
|
799
|
+
sage: b = p.new_variable(binary=True)
|
|
800
|
+
sage: for u,v in graphs.CycleGraph(5).edges(labels=False):
|
|
801
|
+
....: p.add_constraint(b[u]+b[v]<=1)
|
|
802
|
+
sage: p.set_objective(p.sum(b[x] for x in range(5)))
|
|
803
|
+
sage: p.solve()
|
|
804
|
+
2.0
|
|
805
|
+
sage: pb = p.get_backend()
|
|
806
|
+
sage: pb.get_objective_value()
|
|
807
|
+
2.0
|
|
808
|
+
sage: pb.best_known_objective_bound()
|
|
809
|
+
2.0
|
|
810
|
+
"""
|
|
811
|
+
raise NotImplementedError()
|
|
812
|
+
|
|
813
|
+
cpdef get_relative_objective_gap(self):
|
|
814
|
+
r"""
|
|
815
|
+
Return the relative objective gap of the best known solution.
|
|
816
|
+
|
|
817
|
+
For a minimization problem, this value is computed by
|
|
818
|
+
`(\texttt{bestinteger} - \texttt{bestobjective}) / (1e-10 +
|
|
819
|
+
|\texttt{bestobjective}|)`, where ``bestinteger`` is the value returned
|
|
820
|
+
by :meth:`~MixedIntegerLinearProgram.get_objective_value` and
|
|
821
|
+
``bestobjective`` is the value returned by
|
|
822
|
+
:meth:`~MixedIntegerLinearProgram.best_known_objective_bound`. For a
|
|
823
|
+
maximization problem, the value is computed by `(\texttt{bestobjective}
|
|
824
|
+
- \texttt{bestinteger}) / (1e-10 + |\texttt{bestobjective}|)`.
|
|
825
|
+
|
|
826
|
+
.. NOTE::
|
|
827
|
+
|
|
828
|
+
Has no meaning unless ``solve`` has been called before.
|
|
829
|
+
|
|
830
|
+
EXAMPLES::
|
|
831
|
+
|
|
832
|
+
sage: # optional - nonexistent_lp_solver
|
|
833
|
+
sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver")
|
|
834
|
+
sage: b = p.new_variable(binary=True)
|
|
835
|
+
sage: for u,v in graphs.CycleGraph(5).edges(labels=False):
|
|
836
|
+
....: p.add_constraint(b[u]+b[v]<=1)
|
|
837
|
+
sage: p.set_objective(p.sum(b[x] for x in range(5)))
|
|
838
|
+
sage: p.solve()
|
|
839
|
+
2.0
|
|
840
|
+
sage: pb = p.get_backend()
|
|
841
|
+
sage: pb.get_objective_value()
|
|
842
|
+
2.0
|
|
843
|
+
sage: pb.get_relative_objective_gap()
|
|
844
|
+
0.0
|
|
845
|
+
"""
|
|
846
|
+
raise NotImplementedError()
|
|
847
|
+
|
|
848
|
+
cpdef get_variable_value(self, int variable):
|
|
849
|
+
"""
|
|
850
|
+
Return the value of a variable given by the solver.
|
|
851
|
+
|
|
852
|
+
.. NOTE::
|
|
853
|
+
|
|
854
|
+
Behavior is undefined unless ``solve`` has been called before.
|
|
855
|
+
|
|
856
|
+
EXAMPLES::
|
|
857
|
+
|
|
858
|
+
sage: # optional - nonexistent_lp_solver
|
|
859
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
860
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
861
|
+
sage: p.add_variables(2)
|
|
862
|
+
1
|
|
863
|
+
sage: p.add_linear_constraint([(0,1), (1, 2)], None, 3)
|
|
864
|
+
sage: p.set_objective([2, 5])
|
|
865
|
+
sage: p.solve()
|
|
866
|
+
0
|
|
867
|
+
sage: p.get_objective_value()
|
|
868
|
+
7.5
|
|
869
|
+
sage: p.get_variable_value(0)
|
|
870
|
+
0.0
|
|
871
|
+
sage: p.get_variable_value(1)
|
|
872
|
+
1.5
|
|
873
|
+
"""
|
|
874
|
+
|
|
875
|
+
raise NotImplementedError()
|
|
876
|
+
|
|
877
|
+
cpdef int ncols(self) noexcept:
|
|
878
|
+
"""
|
|
879
|
+
Return the number of columns/variables.
|
|
880
|
+
|
|
881
|
+
EXAMPLES::
|
|
882
|
+
|
|
883
|
+
sage: # optional - nonexistent_lp_solver
|
|
884
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
885
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
886
|
+
sage: p.ncols()
|
|
887
|
+
0
|
|
888
|
+
sage: p.add_variables(2)
|
|
889
|
+
1
|
|
890
|
+
sage: p.ncols()
|
|
891
|
+
2
|
|
892
|
+
"""
|
|
893
|
+
|
|
894
|
+
raise NotImplementedError()
|
|
895
|
+
|
|
896
|
+
def _test_ncols_nonnegative(self, **options):
|
|
897
|
+
# Issue #31103: This method has already been migrated to pytest (generic_backend_test)
|
|
898
|
+
# and should be removed as soon as the external sage_numerical_backends packages
|
|
899
|
+
# are updated to invoke pytest as part of their testsuite.
|
|
900
|
+
tester = self._tester(**options)
|
|
901
|
+
p = self
|
|
902
|
+
tester.assertGreaterEqual(self.ncols(), 0)
|
|
903
|
+
|
|
904
|
+
cpdef int nrows(self) noexcept:
|
|
905
|
+
"""
|
|
906
|
+
Return the number of rows/constraints.
|
|
907
|
+
|
|
908
|
+
EXAMPLES::
|
|
909
|
+
|
|
910
|
+
sage: # optional - nonexistent_lp_solver
|
|
911
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
912
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
913
|
+
sage: p.nrows()
|
|
914
|
+
0
|
|
915
|
+
sage: p.add_linear_constraints(2, 2.0, None)
|
|
916
|
+
sage: p.nrows()
|
|
917
|
+
2
|
|
918
|
+
"""
|
|
919
|
+
|
|
920
|
+
raise NotImplementedError()
|
|
921
|
+
|
|
922
|
+
cpdef bint is_maximization(self) noexcept:
|
|
923
|
+
"""
|
|
924
|
+
Test whether the problem is a maximization
|
|
925
|
+
|
|
926
|
+
EXAMPLES::
|
|
927
|
+
|
|
928
|
+
sage: # optional - nonexistent_lp_solver
|
|
929
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
930
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
931
|
+
sage: p.is_maximization()
|
|
932
|
+
True
|
|
933
|
+
sage: p.set_sense(-1)
|
|
934
|
+
sage: p.is_maximization()
|
|
935
|
+
False
|
|
936
|
+
"""
|
|
937
|
+
raise NotImplementedError()
|
|
938
|
+
|
|
939
|
+
cpdef problem_name(self, name=None):
|
|
940
|
+
"""
|
|
941
|
+
Return or define the problem's name.
|
|
942
|
+
|
|
943
|
+
INPUT:
|
|
944
|
+
|
|
945
|
+
- ``name`` -- string; the problem's name. When set to
|
|
946
|
+
``None`` (default), the method returns the problem's name.
|
|
947
|
+
|
|
948
|
+
EXAMPLES::
|
|
949
|
+
|
|
950
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
951
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver") # optional - Nonexistent_LP_solver
|
|
952
|
+
sage: p.problem_name("There once was a french fry") # optional - Nonexistent_LP_solver
|
|
953
|
+
sage: print(p.problem_name()) # optional - Nonexistent_LP_solver
|
|
954
|
+
There once was a french fry
|
|
955
|
+
"""
|
|
956
|
+
|
|
957
|
+
raise NotImplementedError()
|
|
958
|
+
|
|
959
|
+
cpdef write_lp(self, name):
|
|
960
|
+
"""
|
|
961
|
+
Write the problem to a ``.lp`` file.
|
|
962
|
+
|
|
963
|
+
INPUT:
|
|
964
|
+
|
|
965
|
+
- ``filename`` -- string
|
|
966
|
+
|
|
967
|
+
EXAMPLES::
|
|
968
|
+
|
|
969
|
+
sage: # optional - nonexistent_lp_solver
|
|
970
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
971
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
972
|
+
sage: p.add_variables(2)
|
|
973
|
+
2
|
|
974
|
+
sage: p.add_linear_constraint([(0, 1], (1, 2)], None, 3)
|
|
975
|
+
sage: p.set_objective([2, 5])
|
|
976
|
+
sage: from tempfile import NamedTemporaryFile
|
|
977
|
+
sage: with NamedTemporaryFile(suffix='.lp') as f:
|
|
978
|
+
....: p.write_lp(f.name)
|
|
979
|
+
"""
|
|
980
|
+
raise NotImplementedError()
|
|
981
|
+
|
|
982
|
+
cpdef write_mps(self, name, int modern):
|
|
983
|
+
"""
|
|
984
|
+
Write the problem to a ``.mps`` file.
|
|
985
|
+
|
|
986
|
+
INPUT:
|
|
987
|
+
|
|
988
|
+
- ``filename`` -- string
|
|
989
|
+
|
|
990
|
+
EXAMPLES::
|
|
991
|
+
|
|
992
|
+
sage: # optional - nonexistent_lp_solver
|
|
993
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
994
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
995
|
+
sage: p.add_variables(2)
|
|
996
|
+
2
|
|
997
|
+
sage: p.add_linear_constraint([(0, 1), (1, 2)], None, 3)
|
|
998
|
+
sage: p.set_objective([2, 5])
|
|
999
|
+
sage: from tempfile import NamedTemporaryFile
|
|
1000
|
+
sage: with NamedTemporaryFile(suffix='.lp') as f:
|
|
1001
|
+
....: p.write_lp(f.name)
|
|
1002
|
+
"""
|
|
1003
|
+
raise NotImplementedError()
|
|
1004
|
+
|
|
1005
|
+
cpdef copy(self):
|
|
1006
|
+
"""
|
|
1007
|
+
Return a copy of ``self``.
|
|
1008
|
+
|
|
1009
|
+
EXAMPLES::
|
|
1010
|
+
|
|
1011
|
+
sage: # optional - nonexistent_lp_solver
|
|
1012
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1013
|
+
sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver")
|
|
1014
|
+
sage: b = p.new_variable()
|
|
1015
|
+
sage: p.add_constraint(b[1] + b[2] <= 6)
|
|
1016
|
+
sage: p.set_objective(b[1] + b[2])
|
|
1017
|
+
sage: copy(p).solve()
|
|
1018
|
+
6.0
|
|
1019
|
+
"""
|
|
1020
|
+
return self.__copy__()
|
|
1021
|
+
|
|
1022
|
+
# Override this method in backends.
|
|
1023
|
+
cpdef __copy__(self):
|
|
1024
|
+
"""
|
|
1025
|
+
Return a copy of ``self``.
|
|
1026
|
+
|
|
1027
|
+
EXAMPLES::
|
|
1028
|
+
|
|
1029
|
+
sage: # optional - nonexistent_lp_solver
|
|
1030
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1031
|
+
sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver")
|
|
1032
|
+
sage: b = p.new_variable()
|
|
1033
|
+
sage: p.add_constraint(b[1] + b[2] <= 6)
|
|
1034
|
+
sage: p.set_objective(b[1] + b[2])
|
|
1035
|
+
sage: cp = copy(p.get_backend())
|
|
1036
|
+
sage: cp.solve()
|
|
1037
|
+
0
|
|
1038
|
+
sage: cp.get_objective_value()
|
|
1039
|
+
6.0
|
|
1040
|
+
"""
|
|
1041
|
+
raise NotImplementedError()
|
|
1042
|
+
|
|
1043
|
+
def __deepcopy__(self, memo={}):
|
|
1044
|
+
"""
|
|
1045
|
+
Return a deep copy of ``self``.
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: # optional - nonexistent_lp_solver
|
|
1050
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1051
|
+
sage: p = MixedIntegerLinearProgram(solver="Nonexistent_LP_solver")
|
|
1052
|
+
sage: b = p.new_variable()
|
|
1053
|
+
sage: p.add_constraint(b[1] + b[2] <= 6)
|
|
1054
|
+
sage: p.set_objective(b[1] + b[2])
|
|
1055
|
+
sage: cp = deepcopy(p.get_backend())
|
|
1056
|
+
sage: cp.solve()
|
|
1057
|
+
0
|
|
1058
|
+
sage: cp.get_objective_value()
|
|
1059
|
+
6.0
|
|
1060
|
+
"""
|
|
1061
|
+
return self.__copy__()
|
|
1062
|
+
|
|
1063
|
+
cpdef row(self, int i):
|
|
1064
|
+
"""
|
|
1065
|
+
Return a row.
|
|
1066
|
+
|
|
1067
|
+
INPUT:
|
|
1068
|
+
|
|
1069
|
+
- ``index`` -- integer; the constraint's id
|
|
1070
|
+
|
|
1071
|
+
OUTPUT:
|
|
1072
|
+
|
|
1073
|
+
A pair ``(indices, coeffs)`` where ``indices`` lists the
|
|
1074
|
+
entries whose coefficient is nonzero, and to which ``coeffs``
|
|
1075
|
+
associates their coefficient on the model of the
|
|
1076
|
+
``add_linear_constraint`` method.
|
|
1077
|
+
|
|
1078
|
+
EXAMPLES::
|
|
1079
|
+
|
|
1080
|
+
sage: # optional - nonexistent_lp_solver
|
|
1081
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1082
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1083
|
+
sage: p.add_variables(5)
|
|
1084
|
+
4
|
|
1085
|
+
sage: p.add_linear_constraint(zip(range(5), range(5)), 2, 2)
|
|
1086
|
+
sage: p.row(0)
|
|
1087
|
+
([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) ## FIXME: Why backwards?
|
|
1088
|
+
sage: p.row_bounds(0)
|
|
1089
|
+
(2.0, 2.0)
|
|
1090
|
+
"""
|
|
1091
|
+
raise NotImplementedError()
|
|
1092
|
+
|
|
1093
|
+
cpdef row_bounds(self, int index):
|
|
1094
|
+
"""
|
|
1095
|
+
Return the bounds of a specific constraint.
|
|
1096
|
+
|
|
1097
|
+
INPUT:
|
|
1098
|
+
|
|
1099
|
+
- ``index`` -- integer; the constraint's id
|
|
1100
|
+
|
|
1101
|
+
OUTPUT:
|
|
1102
|
+
|
|
1103
|
+
A pair ``(lower_bound, upper_bound)``. Each of them can be set
|
|
1104
|
+
to ``None`` if the constraint is not bounded in the
|
|
1105
|
+
corresponding direction, and is a real value otherwise.
|
|
1106
|
+
|
|
1107
|
+
EXAMPLES::
|
|
1108
|
+
|
|
1109
|
+
sage: # optional - nonexistent_lp_solver
|
|
1110
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1111
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1112
|
+
sage: p.add_variables(5)
|
|
1113
|
+
4
|
|
1114
|
+
sage: p.add_linear_constraint(list(range(5)), list(range(5)), 2, 2)
|
|
1115
|
+
sage: p.row(0)
|
|
1116
|
+
([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) ## FIXME: Why backwards?
|
|
1117
|
+
sage: p.row_bounds(0)
|
|
1118
|
+
(2.0, 2.0)
|
|
1119
|
+
"""
|
|
1120
|
+
raise NotImplementedError()
|
|
1121
|
+
|
|
1122
|
+
cpdef col_bounds(self, int index):
|
|
1123
|
+
"""
|
|
1124
|
+
Return the bounds of a specific variable.
|
|
1125
|
+
|
|
1126
|
+
INPUT:
|
|
1127
|
+
|
|
1128
|
+
- ``index`` -- integer; the variable's id
|
|
1129
|
+
|
|
1130
|
+
OUTPUT:
|
|
1131
|
+
|
|
1132
|
+
A pair ``(lower_bound, upper_bound)``. Each of them can be set
|
|
1133
|
+
to ``None`` if the variable is not bounded in the
|
|
1134
|
+
corresponding direction, and is a real value otherwise.
|
|
1135
|
+
|
|
1136
|
+
EXAMPLES::
|
|
1137
|
+
|
|
1138
|
+
sage: # optional - nonexistent_lp_solver
|
|
1139
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1140
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1141
|
+
sage: p.add_variable()
|
|
1142
|
+
0
|
|
1143
|
+
sage: p.col_bounds(0)
|
|
1144
|
+
(0.0, None)
|
|
1145
|
+
sage: p.variable_upper_bound(0, 5)
|
|
1146
|
+
sage: p.col_bounds(0)
|
|
1147
|
+
(0.0, 5.0)
|
|
1148
|
+
"""
|
|
1149
|
+
raise NotImplementedError()
|
|
1150
|
+
|
|
1151
|
+
cpdef bint is_variable_binary(self, int index) noexcept:
|
|
1152
|
+
"""
|
|
1153
|
+
Test whether the given variable is of binary type.
|
|
1154
|
+
|
|
1155
|
+
INPUT:
|
|
1156
|
+
|
|
1157
|
+
- ``index`` -- integer; the variable's id
|
|
1158
|
+
|
|
1159
|
+
EXAMPLES::
|
|
1160
|
+
|
|
1161
|
+
sage: # optional - nonexistent_lp_solver
|
|
1162
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1163
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1164
|
+
sage: p.ncols()
|
|
1165
|
+
0
|
|
1166
|
+
sage: p.add_variable()
|
|
1167
|
+
0
|
|
1168
|
+
sage: p.set_variable_type(0,0)
|
|
1169
|
+
sage: p.is_variable_binary(0)
|
|
1170
|
+
True
|
|
1171
|
+
"""
|
|
1172
|
+
raise NotImplementedError()
|
|
1173
|
+
|
|
1174
|
+
cpdef bint is_variable_integer(self, int index) noexcept:
|
|
1175
|
+
"""
|
|
1176
|
+
Test whether the given variable is of integer type.
|
|
1177
|
+
|
|
1178
|
+
INPUT:
|
|
1179
|
+
|
|
1180
|
+
- ``index`` -- integer; the variable's id
|
|
1181
|
+
|
|
1182
|
+
EXAMPLES::
|
|
1183
|
+
|
|
1184
|
+
sage: # optional - nonexistent_lp_solver
|
|
1185
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1186
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1187
|
+
sage: p.ncols()
|
|
1188
|
+
0
|
|
1189
|
+
sage: p.add_variable()
|
|
1190
|
+
0
|
|
1191
|
+
sage: p.set_variable_type(0,1)
|
|
1192
|
+
sage: p.is_variable_integer(0)
|
|
1193
|
+
True
|
|
1194
|
+
"""
|
|
1195
|
+
raise NotImplementedError()
|
|
1196
|
+
|
|
1197
|
+
cpdef bint is_variable_continuous(self, int index) noexcept:
|
|
1198
|
+
"""
|
|
1199
|
+
Test whether the given variable is of continuous/real type.
|
|
1200
|
+
|
|
1201
|
+
INPUT:
|
|
1202
|
+
|
|
1203
|
+
- ``index`` -- integer; the variable's id
|
|
1204
|
+
|
|
1205
|
+
EXAMPLES::
|
|
1206
|
+
|
|
1207
|
+
sage: # optional - nonexistent_lp_solver
|
|
1208
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1209
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1210
|
+
sage: p.ncols()
|
|
1211
|
+
0
|
|
1212
|
+
sage: p.add_variable()
|
|
1213
|
+
0
|
|
1214
|
+
sage: p.is_variable_continuous(0)
|
|
1215
|
+
True
|
|
1216
|
+
sage: p.set_variable_type(0,1)
|
|
1217
|
+
sage: p.is_variable_continuous(0)
|
|
1218
|
+
False
|
|
1219
|
+
"""
|
|
1220
|
+
raise NotImplementedError()
|
|
1221
|
+
|
|
1222
|
+
cpdef row_name(self, int index):
|
|
1223
|
+
"""
|
|
1224
|
+
Return the ``index``-th row name.
|
|
1225
|
+
|
|
1226
|
+
INPUT:
|
|
1227
|
+
|
|
1228
|
+
- ``index`` -- integer; the row's id
|
|
1229
|
+
|
|
1230
|
+
EXAMPLES::
|
|
1231
|
+
|
|
1232
|
+
sage: # optional - nonexistent_lp_solver
|
|
1233
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1234
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1235
|
+
sage: p.add_linear_constraints(1, 2, None, names=['Empty constraint 1'])
|
|
1236
|
+
sage: p.row_name(0)
|
|
1237
|
+
'Empty constraint 1'
|
|
1238
|
+
"""
|
|
1239
|
+
raise NotImplementedError()
|
|
1240
|
+
|
|
1241
|
+
cpdef col_name(self, int index):
|
|
1242
|
+
"""
|
|
1243
|
+
Return the ``index``-th column name.
|
|
1244
|
+
|
|
1245
|
+
INPUT:
|
|
1246
|
+
|
|
1247
|
+
- ``index`` -- integer; the column id
|
|
1248
|
+
|
|
1249
|
+
- ``name`` -- (``char *``) its name; when set to ``NULL``
|
|
1250
|
+
(default), the method returns the current name
|
|
1251
|
+
|
|
1252
|
+
EXAMPLES::
|
|
1253
|
+
|
|
1254
|
+
sage: # optional - nonexistent_lp_solver
|
|
1255
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1256
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1257
|
+
sage: p.add_variable(name="I am a variable")
|
|
1258
|
+
1
|
|
1259
|
+
sage: p.col_name(0)
|
|
1260
|
+
'I am a variable'
|
|
1261
|
+
"""
|
|
1262
|
+
raise NotImplementedError()
|
|
1263
|
+
|
|
1264
|
+
def _do_test_problem_data(self, tester, cp):
|
|
1265
|
+
"""
|
|
1266
|
+
TESTS:
|
|
1267
|
+
|
|
1268
|
+
Test, with an actual working backend, that comparing a problem with itself works::
|
|
1269
|
+
|
|
1270
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1271
|
+
sage: p = get_solver(solver='GLPK')
|
|
1272
|
+
sage: tester = p._tester()
|
|
1273
|
+
sage: p._do_test_problem_data(tester, p)
|
|
1274
|
+
"""
|
|
1275
|
+
tester.assertEqual(type(self), type(cp),
|
|
1276
|
+
"Classes do not match")
|
|
1277
|
+
|
|
1278
|
+
def assert_equal_problem_data(method):
|
|
1279
|
+
tester.assertEqual(getattr(self, method)(), getattr(cp, method)(),
|
|
1280
|
+
"{} does not match".format(method))
|
|
1281
|
+
for method in ("ncols", "nrows", "objective_constant_term", "problem_name", "is_maximization"):
|
|
1282
|
+
assert_equal_problem_data(method)
|
|
1283
|
+
|
|
1284
|
+
def assert_equal_col_data(method):
|
|
1285
|
+
for i in range(self.ncols()):
|
|
1286
|
+
tester.assertEqual(getattr(self, method)(i), getattr(cp, method)(i),
|
|
1287
|
+
"{}({}) does not match".format(method, i))
|
|
1288
|
+
for method in ("objective_coefficient", "is_variable_binary", "is_variable_binary", "is_variable_integer",
|
|
1289
|
+
"is_variable_continuous", "col_bounds", "col_name"):
|
|
1290
|
+
# don't test variable_lower_bound, variable_upper_bound because we already test col_bounds.
|
|
1291
|
+
# TODO: Add a test elsewhere to ensure that variable_lower_bound, variable_upper_bound
|
|
1292
|
+
# are consistent with col_bounds.
|
|
1293
|
+
assert_equal_col_data(method)
|
|
1294
|
+
|
|
1295
|
+
def assert_equal_row_data(method):
|
|
1296
|
+
for i in range(self.nrows()):
|
|
1297
|
+
tester.assertEqual(getattr(self, method)(i), getattr(cp, method)(i),
|
|
1298
|
+
"{}({}) does not match".format(method, i))
|
|
1299
|
+
for method in ("row_bounds", "row", "row_name"):
|
|
1300
|
+
assert_equal_row_data(method)
|
|
1301
|
+
|
|
1302
|
+
def _test_copy(self, **options):
|
|
1303
|
+
"""
|
|
1304
|
+
Test whether the backend can be copied
|
|
1305
|
+
and at least the problem data of the copy is equal to that of the original.
|
|
1306
|
+
Does not test whether solutions or solver parameters are copied.
|
|
1307
|
+
"""
|
|
1308
|
+
tester = self._tester(**options)
|
|
1309
|
+
cp = copy(self)
|
|
1310
|
+
self._do_test_problem_data(tester, cp)
|
|
1311
|
+
|
|
1312
|
+
def _test_copy_does_not_share_data(self, **options):
|
|
1313
|
+
"""
|
|
1314
|
+
Test whether copy makes an independent copy of the backend.
|
|
1315
|
+
"""
|
|
1316
|
+
tester = self._tester(**options)
|
|
1317
|
+
|
|
1318
|
+
cp = copy(self)
|
|
1319
|
+
cpcp = copy(cp)
|
|
1320
|
+
del cp
|
|
1321
|
+
self._do_test_problem_data(tester, cpcp)
|
|
1322
|
+
|
|
1323
|
+
# TODO: We should have a more systematic way of generating MIPs for testing.
|
|
1324
|
+
|
|
1325
|
+
@classmethod
|
|
1326
|
+
def _test_copy_some_mips(cls, tester=None, **options):
|
|
1327
|
+
p = cls() # fresh instance of the backend
|
|
1328
|
+
if tester is None:
|
|
1329
|
+
tester = p._tester(**options)
|
|
1330
|
+
# From doctest of GenericBackend.solve:
|
|
1331
|
+
p.add_linear_constraints(5, 0, None)
|
|
1332
|
+
try:
|
|
1333
|
+
# p.add_col(range(5), range(5)) -- bad test because COIN sparsifies the 0s away on copy
|
|
1334
|
+
p.add_col(list(range(5)), list(range(1, 6)))
|
|
1335
|
+
except NotImplementedError:
|
|
1336
|
+
# Gurobi does not implement add_col
|
|
1337
|
+
pass
|
|
1338
|
+
# From doctest of GenericBackend.problem_name:
|
|
1339
|
+
p.problem_name("There once was a french fry")
|
|
1340
|
+
|
|
1341
|
+
p._test_copy(**options)
|
|
1342
|
+
p._test_copy_does_not_share_data(**options)
|
|
1343
|
+
|
|
1344
|
+
cpdef variable_upper_bound(self, int index, value=False):
|
|
1345
|
+
"""
|
|
1346
|
+
Return or define the upper bound on a variable.
|
|
1347
|
+
|
|
1348
|
+
INPUT:
|
|
1349
|
+
|
|
1350
|
+
- ``index`` -- integer; the variable's id
|
|
1351
|
+
|
|
1352
|
+
- ``value`` -- real value, or ``None`` to mean that the
|
|
1353
|
+
variable has not upper bound. When set to ``False``
|
|
1354
|
+
(default), the method returns the current value.
|
|
1355
|
+
|
|
1356
|
+
EXAMPLES::
|
|
1357
|
+
|
|
1358
|
+
sage: # optional - nonexistent_lp_solver
|
|
1359
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1360
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1361
|
+
sage: p.add_variable()
|
|
1362
|
+
0
|
|
1363
|
+
sage: p.col_bounds(0)
|
|
1364
|
+
(0.0, None)
|
|
1365
|
+
sage: p.variable_upper_bound(0, 5)
|
|
1366
|
+
sage: p.col_bounds(0)
|
|
1367
|
+
(0.0, 5.0)
|
|
1368
|
+
"""
|
|
1369
|
+
raise NotImplementedError()
|
|
1370
|
+
|
|
1371
|
+
cpdef variable_lower_bound(self, int index, value=False):
|
|
1372
|
+
"""
|
|
1373
|
+
Return or define the lower bound on a variable.
|
|
1374
|
+
|
|
1375
|
+
INPUT:
|
|
1376
|
+
|
|
1377
|
+
- ``index`` -- integer; the variable's id
|
|
1378
|
+
|
|
1379
|
+
- ``value`` -- real value, or ``None`` to mean that the
|
|
1380
|
+
variable has not lower bound. When set to ``False``
|
|
1381
|
+
(default), the method returns the current value.
|
|
1382
|
+
|
|
1383
|
+
EXAMPLES::
|
|
1384
|
+
|
|
1385
|
+
sage: # optional - nonexistent_lp_solver
|
|
1386
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1387
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1388
|
+
sage: p.add_variable()
|
|
1389
|
+
0
|
|
1390
|
+
sage: p.col_bounds(0)
|
|
1391
|
+
(0.0, None)
|
|
1392
|
+
sage: p.variable_lower_bound(0, 5)
|
|
1393
|
+
sage: p.col_bounds(0)
|
|
1394
|
+
(5.0, None)
|
|
1395
|
+
"""
|
|
1396
|
+
raise NotImplementedError()
|
|
1397
|
+
|
|
1398
|
+
cpdef solver_parameter(self, name, value=None):
|
|
1399
|
+
"""
|
|
1400
|
+
Return or define a solver parameter.
|
|
1401
|
+
|
|
1402
|
+
INPUT:
|
|
1403
|
+
|
|
1404
|
+
- ``name`` -- string; the parameter
|
|
1405
|
+
|
|
1406
|
+
- ``value`` -- the parameter's value if it is to be defined,
|
|
1407
|
+
or ``None`` (default) to obtain its current value
|
|
1408
|
+
|
|
1409
|
+
.. NOTE::
|
|
1410
|
+
|
|
1411
|
+
The list of available parameters is available at
|
|
1412
|
+
:meth:`~sage.numerical.mip.MixedIntegerLinearProgram.solver_parameter`.
|
|
1413
|
+
|
|
1414
|
+
EXAMPLES::
|
|
1415
|
+
|
|
1416
|
+
sage: # optional - nonexistent_lp_solver
|
|
1417
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1418
|
+
sage: p = get_solver(solver="Nonexistent_LP_solver")
|
|
1419
|
+
sage: p.solver_parameter("timelimit")
|
|
1420
|
+
sage: p.solver_parameter("timelimit", 60)
|
|
1421
|
+
sage: p.solver_parameter("timelimit")
|
|
1422
|
+
"""
|
|
1423
|
+
raise NotImplementedError()
|
|
1424
|
+
|
|
1425
|
+
cpdef bint is_variable_basic(self, int index) noexcept:
|
|
1426
|
+
"""
|
|
1427
|
+
Test whether the given variable is basic.
|
|
1428
|
+
|
|
1429
|
+
This assumes that the problem has been solved with the simplex method
|
|
1430
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1431
|
+
|
|
1432
|
+
INPUT:
|
|
1433
|
+
|
|
1434
|
+
- ``index`` -- integer; the variable's id
|
|
1435
|
+
|
|
1436
|
+
EXAMPLES::
|
|
1437
|
+
|
|
1438
|
+
sage: # optional - nonexistent_lp_solver
|
|
1439
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,
|
|
1440
|
+
....: solver="Nonexistent_LP_solver")
|
|
1441
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1442
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1443
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1444
|
+
sage: p.set_objective(5.5 * x[0] - 3 * x[1])
|
|
1445
|
+
sage: b = p.get_backend()
|
|
1446
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1447
|
+
sage: b.solve()
|
|
1448
|
+
0
|
|
1449
|
+
sage: b.is_variable_basic(0)
|
|
1450
|
+
True
|
|
1451
|
+
sage: b.is_variable_basic(1)
|
|
1452
|
+
False
|
|
1453
|
+
"""
|
|
1454
|
+
raise NotImplementedError()
|
|
1455
|
+
|
|
1456
|
+
cpdef bint is_variable_nonbasic_at_lower_bound(self, int index) noexcept:
|
|
1457
|
+
"""
|
|
1458
|
+
Test whether the given variable is nonbasic at lower bound.
|
|
1459
|
+
|
|
1460
|
+
This assumes that the problem has been solved with the simplex method
|
|
1461
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1462
|
+
|
|
1463
|
+
INPUT:
|
|
1464
|
+
|
|
1465
|
+
- ``index`` -- integer; the variable's id
|
|
1466
|
+
|
|
1467
|
+
EXAMPLES::
|
|
1468
|
+
|
|
1469
|
+
sage: # optional - nonexistent_lp_solver
|
|
1470
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,
|
|
1471
|
+
....: solver="Nonexistent_LP_solver")
|
|
1472
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1473
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1474
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1475
|
+
sage: p.set_objective(5.5 * x[0] - 3 * x[1])
|
|
1476
|
+
sage: b = p.get_backend()
|
|
1477
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1478
|
+
sage: b.solve()
|
|
1479
|
+
0
|
|
1480
|
+
sage: b.is_variable_nonbasic_at_lower_bound(0)
|
|
1481
|
+
False
|
|
1482
|
+
sage: b.is_variable_nonbasic_at_lower_bound(1)
|
|
1483
|
+
True
|
|
1484
|
+
"""
|
|
1485
|
+
raise NotImplementedError()
|
|
1486
|
+
|
|
1487
|
+
cpdef bint is_slack_variable_basic(self, int index) noexcept:
|
|
1488
|
+
"""
|
|
1489
|
+
Test whether the slack variable of the given row is basic.
|
|
1490
|
+
|
|
1491
|
+
This assumes that the problem has been solved with the simplex method
|
|
1492
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1493
|
+
|
|
1494
|
+
INPUT:
|
|
1495
|
+
|
|
1496
|
+
- ``index`` -- integer; the variable's id
|
|
1497
|
+
|
|
1498
|
+
EXAMPLES::
|
|
1499
|
+
|
|
1500
|
+
sage: # optional - nonexistent_lp_solver
|
|
1501
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,
|
|
1502
|
+
....: solver="Nonexistent_LP_solver")
|
|
1503
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1504
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1505
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1506
|
+
sage: p.set_objective(5.5 * x[0] - 3 * x[1])
|
|
1507
|
+
sage: b = p.get_backend()
|
|
1508
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1509
|
+
sage: b.solve()
|
|
1510
|
+
0
|
|
1511
|
+
sage: b.is_slack_variable_basic(0)
|
|
1512
|
+
True
|
|
1513
|
+
sage: b.is_slack_variable_basic(1)
|
|
1514
|
+
False
|
|
1515
|
+
"""
|
|
1516
|
+
raise NotImplementedError()
|
|
1517
|
+
|
|
1518
|
+
cpdef bint is_slack_variable_nonbasic_at_lower_bound(self, int index) noexcept:
|
|
1519
|
+
"""
|
|
1520
|
+
Test whether the given variable is nonbasic at lower bound.
|
|
1521
|
+
|
|
1522
|
+
This assumes that the problem has been solved with the simplex method
|
|
1523
|
+
and a basis is available. Otherwise an exception will be raised.
|
|
1524
|
+
|
|
1525
|
+
INPUT:
|
|
1526
|
+
|
|
1527
|
+
- ``index`` -- integer; the variable's id
|
|
1528
|
+
|
|
1529
|
+
EXAMPLES::
|
|
1530
|
+
|
|
1531
|
+
sage: # optional - nonexistent_lp_solver
|
|
1532
|
+
sage: p = MixedIntegerLinearProgram(maximization=True,
|
|
1533
|
+
....: solver="Nonexistent_LP_solver")
|
|
1534
|
+
sage: x = p.new_variable(nonnegative=True)
|
|
1535
|
+
sage: p.add_constraint(-x[0] + x[1] <= 2)
|
|
1536
|
+
sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17)
|
|
1537
|
+
sage: p.set_objective(5.5 * x[0] - 3 * x[1])
|
|
1538
|
+
sage: b = p.get_backend()
|
|
1539
|
+
sage: # Backend-specific commands to instruct solver to use simplex method here
|
|
1540
|
+
sage: b.solve()
|
|
1541
|
+
0
|
|
1542
|
+
sage: b.is_slack_variable_nonbasic_at_lower_bound(0)
|
|
1543
|
+
False
|
|
1544
|
+
sage: b.is_slack_variable_nonbasic_at_lower_bound(1)
|
|
1545
|
+
True
|
|
1546
|
+
"""
|
|
1547
|
+
raise NotImplementedError()
|
|
1548
|
+
|
|
1549
|
+
@classmethod
|
|
1550
|
+
def _test_solve_trac_18572(cls, tester=None, **options):
|
|
1551
|
+
"""
|
|
1552
|
+
Run tests regarding :issue:`18572`::
|
|
1553
|
+
|
|
1554
|
+
TESTS::
|
|
1555
|
+
|
|
1556
|
+
sage: from sage.numerical.backends.generic_backend import GenericBackend
|
|
1557
|
+
sage: p = GenericBackend()
|
|
1558
|
+
sage: p._test_solve_trac_18572()
|
|
1559
|
+
Traceback (most recent call last):
|
|
1560
|
+
...
|
|
1561
|
+
NotImplementedError
|
|
1562
|
+
"""
|
|
1563
|
+
p = cls() # fresh instance of the backend
|
|
1564
|
+
if tester is None:
|
|
1565
|
+
tester = p._tester(**options)
|
|
1566
|
+
tester.assertIsNone(p.set_sense(-1))
|
|
1567
|
+
tester.assertEqual(p.add_variable(0, None, False, True, False, 0, None), 0)
|
|
1568
|
+
tester.assertIsNone(p.set_variable_type(0, -1))
|
|
1569
|
+
tester.assertEqual(p.add_variable(0, None, False, True, False, 0, None), 1)
|
|
1570
|
+
tester.assertIsNone(p.set_variable_type(1, -1))
|
|
1571
|
+
tester.assertEqual(p.add_variable(None, None, False, True, False, 0, None), 2)
|
|
1572
|
+
tester.assertIsNone(p.set_variable_type(2, -1))
|
|
1573
|
+
tester.assertIsNone(p.add_linear_constraint([(0, 2), (1, 1), (2, -1)], None, 0, None))
|
|
1574
|
+
tester.assertIsNone(p.add_linear_constraint([(0, 1), (1, 3), (2, -1)], None, 0, None))
|
|
1575
|
+
tester.assertIsNone(p.add_linear_constraint([(0, 1), (1, 1)], 1, 1, None))
|
|
1576
|
+
tester.assertEqual(p.ncols(), 3)
|
|
1577
|
+
tester.assertIsNone(p.set_objective([0, 0, 1], 0))
|
|
1578
|
+
tester.assertEqual(p.solve(), 0)
|
|
1579
|
+
tester.assertAlmostEqual(p.get_objective_value(), 1.66666666667)
|
|
1580
|
+
tester.assertAlmostEqual(p.get_variable_value(0), 0.666666666667)
|
|
1581
|
+
tester.assertAlmostEqual(p.get_variable_value(1), 0.333333333333)
|
|
1582
|
+
|
|
1583
|
+
|
|
1584
|
+
default_solver = None
|
|
1585
|
+
|
|
1586
|
+
|
|
1587
|
+
def default_mip_solver(solver=None):
|
|
1588
|
+
"""
|
|
1589
|
+
Return/set the default MILP solver used by Sage.
|
|
1590
|
+
|
|
1591
|
+
INPUT:
|
|
1592
|
+
|
|
1593
|
+
- ``solver`` -- one of the following:
|
|
1594
|
+
|
|
1595
|
+
- a string indicating one of the available solvers
|
|
1596
|
+
(see :class:`MixedIntegerLinearProgram`);
|
|
1597
|
+
|
|
1598
|
+
- a callable (typically a subclass of
|
|
1599
|
+
:class:`sage.numerical.backends.generic_backend.GenericBackend`);
|
|
1600
|
+
|
|
1601
|
+
- ``None`` -- (default) in which case the current default solver
|
|
1602
|
+
is returned; this is either a string or a callable
|
|
1603
|
+
|
|
1604
|
+
OUTPUT:
|
|
1605
|
+
|
|
1606
|
+
This function returns the current default solver's name if ``solver = None``
|
|
1607
|
+
(default). Otherwise, it sets the default solver to the one given. If this
|
|
1608
|
+
solver does not exist, or is not available, a :exc:`ValueError` exception is
|
|
1609
|
+
raised.
|
|
1610
|
+
|
|
1611
|
+
EXAMPLES::
|
|
1612
|
+
|
|
1613
|
+
sage: former_solver = default_mip_solver()
|
|
1614
|
+
sage: default_mip_solver("GLPK")
|
|
1615
|
+
sage: default_mip_solver()
|
|
1616
|
+
'Glpk'
|
|
1617
|
+
sage: default_mip_solver("PPL")
|
|
1618
|
+
sage: default_mip_solver()
|
|
1619
|
+
'Ppl'
|
|
1620
|
+
sage: default_mip_solver("GUROBI") # random
|
|
1621
|
+
Traceback (most recent call last):
|
|
1622
|
+
...
|
|
1623
|
+
ValueError: Gurobi is not available. Please refer to the documentation to install it.
|
|
1624
|
+
sage: default_mip_solver("Yeahhhhhhhhhhh")
|
|
1625
|
+
Traceback (most recent call last):
|
|
1626
|
+
...
|
|
1627
|
+
ValueError: 'solver' should be set to ...
|
|
1628
|
+
sage: default_mip_solver(former_solver)
|
|
1629
|
+
"""
|
|
1630
|
+
global default_solver
|
|
1631
|
+
|
|
1632
|
+
if solver is None:
|
|
1633
|
+
|
|
1634
|
+
if default_solver is not None:
|
|
1635
|
+
return default_solver
|
|
1636
|
+
|
|
1637
|
+
else:
|
|
1638
|
+
for s in ["Cplex", "Gurobi", "Cvxpy/cbc", "Coin", "Glpk", "SCIP"]:
|
|
1639
|
+
try:
|
|
1640
|
+
default_mip_solver(s)
|
|
1641
|
+
return s
|
|
1642
|
+
except ValueError:
|
|
1643
|
+
pass
|
|
1644
|
+
|
|
1645
|
+
if callable(solver):
|
|
1646
|
+
default_solver = solver
|
|
1647
|
+
return
|
|
1648
|
+
|
|
1649
|
+
solver = solver.capitalize()
|
|
1650
|
+
|
|
1651
|
+
if solver == "Cplex":
|
|
1652
|
+
try:
|
|
1653
|
+
from sage_numerical_backends_cplex.cplex_backend import CPLEXBackend
|
|
1654
|
+
default_solver = solver
|
|
1655
|
+
except ImportError:
|
|
1656
|
+
raise ValueError("CPLEX is not available. Please refer to the documentation to install it.")
|
|
1657
|
+
|
|
1658
|
+
elif solver == "Coin":
|
|
1659
|
+
try:
|
|
1660
|
+
from sage_numerical_backends_coin.coin_backend import CoinBackend
|
|
1661
|
+
default_solver = solver
|
|
1662
|
+
except ImportError:
|
|
1663
|
+
raise ValueError("COIN is not available. Please refer to the documentation to install it.")
|
|
1664
|
+
|
|
1665
|
+
elif solver == "Cvxopt":
|
|
1666
|
+
try:
|
|
1667
|
+
from sage.numerical.backends.cvxopt_backend import CVXOPTBackend
|
|
1668
|
+
default_solver = solver
|
|
1669
|
+
except ImportError:
|
|
1670
|
+
raise ValueError("CVXOPT is not available. Please refer to the documentation to install it.")
|
|
1671
|
+
|
|
1672
|
+
elif solver == "Ppl":
|
|
1673
|
+
try:
|
|
1674
|
+
from sage.numerical.backends.ppl_backend import PPLBackend
|
|
1675
|
+
default_solver = solver
|
|
1676
|
+
except ImportError:
|
|
1677
|
+
raise ValueError("PPL is not available. Please refer to the documentation to install it.")
|
|
1678
|
+
|
|
1679
|
+
elif solver == "Gurobi":
|
|
1680
|
+
try:
|
|
1681
|
+
from sage_numerical_backends_gurobi.gurobi_backend import GurobiBackend
|
|
1682
|
+
default_solver = solver
|
|
1683
|
+
except ImportError:
|
|
1684
|
+
raise ValueError("Gurobi is not available. Please refer to the documentation to install it.")
|
|
1685
|
+
|
|
1686
|
+
elif solver == "Glpk" or solver == "Glpk/exact":
|
|
1687
|
+
try:
|
|
1688
|
+
from sage.numerical.backends.glpk_backend import GLPKBackend
|
|
1689
|
+
default_solver = solver
|
|
1690
|
+
except ImportError:
|
|
1691
|
+
raise ValueError("GLPK is not available. Please refer to the documentation to install it.")
|
|
1692
|
+
|
|
1693
|
+
elif solver == "Interactivelp":
|
|
1694
|
+
default_solver = solver
|
|
1695
|
+
|
|
1696
|
+
elif solver == "Cvxpy":
|
|
1697
|
+
try:
|
|
1698
|
+
from sage.numerical.backends.cvxpy_backend import CVXPYBackend
|
|
1699
|
+
except ImportError:
|
|
1700
|
+
raise ValueError("CVXPY is not available. Please refer to the documentation to install it.")
|
|
1701
|
+
else:
|
|
1702
|
+
assert CVXPYBackend
|
|
1703
|
+
default_solver = solver
|
|
1704
|
+
|
|
1705
|
+
elif solver.startswith("Cvxpy"):
|
|
1706
|
+
try:
|
|
1707
|
+
s = get_solver(solver=solver)
|
|
1708
|
+
s.solve()
|
|
1709
|
+
except Exception as e:
|
|
1710
|
+
raise ValueError(f"{solver} is not available: {e}. Please refer to the documentation to install it.")
|
|
1711
|
+
else:
|
|
1712
|
+
default_solver = solver
|
|
1713
|
+
|
|
1714
|
+
elif solver == "Scip":
|
|
1715
|
+
try:
|
|
1716
|
+
from sage.numerical.backends.scip_backend import SCIPBackend
|
|
1717
|
+
default_solver = solver
|
|
1718
|
+
except ImportError:
|
|
1719
|
+
raise ValueError("SCIP is not available. Please refer to the documentation to install it.")
|
|
1720
|
+
|
|
1721
|
+
else:
|
|
1722
|
+
raise ValueError("'solver' should be set to 'GLPK', 'Coin', 'CPLEX', 'CVXOPT', 'CVXPY', 'Gurobi', 'PPL', 'SCIP', 'InteractiveLP', a callable, or None.")
|
|
1723
|
+
|
|
1724
|
+
|
|
1725
|
+
cpdef GenericBackend get_solver(constraint_generation=False, solver=None, base_ring=None):
|
|
1726
|
+
"""
|
|
1727
|
+
Return a solver according to the given preferences.
|
|
1728
|
+
|
|
1729
|
+
INPUT:
|
|
1730
|
+
|
|
1731
|
+
- ``solver`` -- one of the following:
|
|
1732
|
+
|
|
1733
|
+
- a string indicating one of the available solvers
|
|
1734
|
+
(see :class:`MixedIntegerLinearProgram`);
|
|
1735
|
+
|
|
1736
|
+
- ``None`` -- (default) in which case the default solver is used
|
|
1737
|
+
(see :func:`default_mip_solver`);
|
|
1738
|
+
|
|
1739
|
+
- or a callable (such as a class), in which case it is called,
|
|
1740
|
+
and its result is returned.
|
|
1741
|
+
|
|
1742
|
+
- ``base_ring`` -- if not ``None``, request a solver that works over this
|
|
1743
|
+
(ordered) field. If ``base_ring`` is not a field, its fraction field
|
|
1744
|
+
is used.
|
|
1745
|
+
|
|
1746
|
+
For example, is ``base_ring=ZZ`` is provided, the solver will work over
|
|
1747
|
+
the rational numbers. This is unrelated to whether variables are
|
|
1748
|
+
constrained to be integers or not.
|
|
1749
|
+
|
|
1750
|
+
- ``constraint_generation`` -- only used when ``solver=None``:
|
|
1751
|
+
|
|
1752
|
+
- When set to ``True``, after solving the ``MixedIntegerLinearProgram``,
|
|
1753
|
+
it is possible to add a constraint, and then solve it again.
|
|
1754
|
+
The effect is that solvers that do not support this feature will not be
|
|
1755
|
+
used. (Coin and SCIP are such solvers.)
|
|
1756
|
+
|
|
1757
|
+
- Defaults to ``False``.
|
|
1758
|
+
|
|
1759
|
+
.. SEEALSO::
|
|
1760
|
+
|
|
1761
|
+
- :func:`default_mip_solver` -- returns/sets the default MIP solver
|
|
1762
|
+
|
|
1763
|
+
EXAMPLES::
|
|
1764
|
+
|
|
1765
|
+
sage: from sage.numerical.backends.generic_backend import get_solver
|
|
1766
|
+
sage: p = get_solver()
|
|
1767
|
+
sage: p = get_solver(base_ring=RDF)
|
|
1768
|
+
sage: p.base_ring()
|
|
1769
|
+
Real Double Field
|
|
1770
|
+
sage: p = get_solver(base_ring=QQ); p
|
|
1771
|
+
<...sage.numerical.backends.ppl_backend.PPLBackend...>
|
|
1772
|
+
sage: p = get_solver(base_ring=ZZ); p
|
|
1773
|
+
<...sage.numerical.backends.ppl_backend.PPLBackend...>
|
|
1774
|
+
sage: p.base_ring()
|
|
1775
|
+
Rational Field
|
|
1776
|
+
sage: p = get_solver(base_ring=AA); p # needs sage.rings.number_field
|
|
1777
|
+
<...sage.numerical.backends.interactivelp_backend.InteractiveLPBackend...>
|
|
1778
|
+
sage: p.base_ring() # needs sage.rings.number_field
|
|
1779
|
+
Algebraic Real Field
|
|
1780
|
+
|
|
1781
|
+
sage: # needs sage.groups sage.rings.number_field
|
|
1782
|
+
sage: d = polytopes.dodecahedron()
|
|
1783
|
+
sage: p = get_solver(base_ring=d.base_ring()); p
|
|
1784
|
+
<...sage.numerical.backends.interactivelp_backend.InteractiveLPBackend...>
|
|
1785
|
+
sage: p.base_ring()
|
|
1786
|
+
Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?
|
|
1787
|
+
sage: p = get_solver(solver='InteractiveLP', base_ring=QQ); p
|
|
1788
|
+
<...sage.numerical.backends.interactivelp_backend.InteractiveLPBackend...>
|
|
1789
|
+
sage: p.base_ring()
|
|
1790
|
+
Rational Field
|
|
1791
|
+
|
|
1792
|
+
Passing a callable as the ``solver``::
|
|
1793
|
+
|
|
1794
|
+
sage: from sage.numerical.backends.glpk_backend import GLPKBackend
|
|
1795
|
+
sage: p = get_solver(solver=GLPKBackend); p
|
|
1796
|
+
<...sage.numerical.backends.glpk_backend.GLPKBackend...>
|
|
1797
|
+
|
|
1798
|
+
Passing a callable that customizes a backend::
|
|
1799
|
+
|
|
1800
|
+
sage: def glpk_exact_solver():
|
|
1801
|
+
....: from sage.numerical.backends.generic_backend import get_solver
|
|
1802
|
+
....: b = get_solver(solver='GLPK')
|
|
1803
|
+
....: b.solver_parameter('simplex_or_intopt', 'exact_simplex_only')
|
|
1804
|
+
....: return b
|
|
1805
|
+
sage: codes.bounds.delsarte_bound_additive_hamming_space(11,3,4,solver=glpk_exact_solver) # long time
|
|
1806
|
+
8
|
|
1807
|
+
|
|
1808
|
+
TESTS:
|
|
1809
|
+
|
|
1810
|
+
Test that it works when the default solver is a callable, see :issue:`28914`::
|
|
1811
|
+
|
|
1812
|
+
sage: old_default = default_mip_solver()
|
|
1813
|
+
sage: from sage.numerical.backends.glpk_backend import GLPKBackend
|
|
1814
|
+
sage: default_mip_solver(GLPKBackend)
|
|
1815
|
+
sage: M = MixedIntegerLinearProgram() # indirect doctest
|
|
1816
|
+
sage: M.get_backend()
|
|
1817
|
+
<...GLPKBackend...>
|
|
1818
|
+
sage: default_mip_solver(old_default)
|
|
1819
|
+
"""
|
|
1820
|
+
if solver is None:
|
|
1821
|
+
|
|
1822
|
+
solver = default_mip_solver()
|
|
1823
|
+
|
|
1824
|
+
if base_ring is not None:
|
|
1825
|
+
base_ring = base_ring.fraction_field()
|
|
1826
|
+
from sage.rings.rational_field import QQ
|
|
1827
|
+
from sage.rings.real_double import RDF
|
|
1828
|
+
if base_ring is QQ:
|
|
1829
|
+
solver = "Ppl"
|
|
1830
|
+
elif solver in ["Interactivelp", "Ppl"] and not base_ring.is_exact():
|
|
1831
|
+
solver = "Glpk"
|
|
1832
|
+
elif base_ring is not RDF:
|
|
1833
|
+
solver = "Interactivelp"
|
|
1834
|
+
|
|
1835
|
+
# We do not want to use Coin for constraint_generation. It just does not
|
|
1836
|
+
# work
|
|
1837
|
+
if solver in ("Coin", "SCIP") and constraint_generation:
|
|
1838
|
+
solver = "Glpk"
|
|
1839
|
+
|
|
1840
|
+
if callable(solver):
|
|
1841
|
+
kwds = {}
|
|
1842
|
+
if base_ring is not None:
|
|
1843
|
+
kwds['base_ring']=base_ring
|
|
1844
|
+
return solver(**kwds)
|
|
1845
|
+
|
|
1846
|
+
else:
|
|
1847
|
+
solver = solver.capitalize()
|
|
1848
|
+
|
|
1849
|
+
if solver == "Coin":
|
|
1850
|
+
from sage_numerical_backends_coin.coin_backend import CoinBackend
|
|
1851
|
+
return CoinBackend()
|
|
1852
|
+
|
|
1853
|
+
elif solver == "Glpk":
|
|
1854
|
+
from sage.numerical.backends.glpk_backend import GLPKBackend
|
|
1855
|
+
return GLPKBackend()
|
|
1856
|
+
|
|
1857
|
+
elif solver == "Glpk/exact":
|
|
1858
|
+
from sage.numerical.backends.glpk_exact_backend import GLPKExactBackend
|
|
1859
|
+
return GLPKExactBackend()
|
|
1860
|
+
|
|
1861
|
+
elif solver == "Cplex":
|
|
1862
|
+
from sage_numerical_backends_cplex.cplex_backend import CPLEXBackend
|
|
1863
|
+
return CPLEXBackend()
|
|
1864
|
+
|
|
1865
|
+
elif solver == "Cvxopt":
|
|
1866
|
+
from sage.numerical.backends.cvxopt_backend import CVXOPTBackend
|
|
1867
|
+
return CVXOPTBackend()
|
|
1868
|
+
|
|
1869
|
+
elif solver == "Gurobi":
|
|
1870
|
+
from sage_numerical_backends_gurobi.gurobi_backend import GurobiBackend
|
|
1871
|
+
return GurobiBackend()
|
|
1872
|
+
|
|
1873
|
+
elif solver == "Ppl":
|
|
1874
|
+
from sage.numerical.backends.ppl_backend import PPLBackend
|
|
1875
|
+
return PPLBackend(base_ring=base_ring)
|
|
1876
|
+
|
|
1877
|
+
elif solver == "Interactivelp":
|
|
1878
|
+
from sage.numerical.backends.interactivelp_backend import InteractiveLPBackend
|
|
1879
|
+
return InteractiveLPBackend(base_ring=base_ring)
|
|
1880
|
+
|
|
1881
|
+
elif solver.startswith("Cvxpy"):
|
|
1882
|
+
from sage.numerical.backends.cvxpy_backend import CVXPYBackend
|
|
1883
|
+
if solver == "Cvxpy":
|
|
1884
|
+
return CVXPYBackend()
|
|
1885
|
+
if solver.startswith("Cvxpy/"):
|
|
1886
|
+
return CVXPYBackend(cvxpy_solver=solver[len("Cvxpy/"):])
|
|
1887
|
+
|
|
1888
|
+
elif solver == "Scip":
|
|
1889
|
+
from sage.numerical.backends.scip_backend import SCIPBackend
|
|
1890
|
+
return SCIPBackend()
|
|
1891
|
+
|
|
1892
|
+
else:
|
|
1893
|
+
raise ValueError("'solver' should be set to 'GLPK', 'GLPK/exact', 'Coin', 'CPLEX', 'CVXOPT', 'CVXPY', 'Gurobi', 'PPL', 'SCIP', 'InteractiveLP', None (in which case the default one is used), or a callable.")
|