passagemath-modules 10.5.32__cp310-cp310-macosx_14_0_arm64.whl → 10.6.20__cp310-cp310-macosx_14_0_arm64.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.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- {passagemath_modules-10.5.32.dist-info → passagemath_modules-10.6.20.dist-info}/METADATA +51 -46
- {passagemath_modules-10.5.32.dist-info → passagemath_modules-10.6.20.dist-info}/RECORD +333 -323
- {passagemath_modules-10.5.32.dist-info → passagemath_modules-10.6.20.dist-info}/WHEEL +1 -1
- passagemath_modules.dylibs/libgcc_s.1.1.dylib +0 -0
- passagemath_modules.dylibs/libgfortran.5.dylib +0 -0
- passagemath_modules.dylibs/libgsl.28.dylib +0 -0
- passagemath_modules.dylibs/libmpc.3.dylib +0 -0
- passagemath_modules.dylibs/libopenblasp-r0.3.29.dylib +0 -0
- passagemath_modules.dylibs/libquadmath.0.dylib +0 -0
- sage/algebras/clifford_algebra.py +2 -2
- sage/algebras/clifford_algebra_element.cpython-310-darwin.so +0 -0
- sage/algebras/clifford_algebra_element.pyx +4 -2
- sage/algebras/exterior_algebra_groebner.cpython-310-darwin.so +0 -0
- sage/algebras/exterior_algebra_groebner.pyx +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +83 -5
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-310-darwin.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +28 -3
- sage/algebras/finite_gca.py +1 -1
- sage/algebras/lie_algebras/bgg_dual_module.py +18 -11
- sage/algebras/lie_algebras/classical_lie_algebra.py +3 -3
- sage/algebras/lie_algebras/examples.py +2 -2
- sage/algebras/lie_algebras/free_lie_algebra.py +1 -1
- sage/algebras/lie_algebras/heisenberg.py +4 -4
- sage/algebras/lie_algebras/lie_algebra.py +1 -1
- sage/algebras/lie_algebras/lie_algebra_element.cpython-310-darwin.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +65 -28
- sage/algebras/lie_algebras/quotient.py +40 -29
- sage/algebras/lie_algebras/subalgebra.py +76 -53
- sage/algebras/lie_algebras/verma_module.py +1 -3
- sage/algebras/octonion_algebra.cpython-310-darwin.so +0 -0
- sage/algebras/octonion_algebra.pyx +1 -1
- sage/algebras/orlik_solomon.py +4 -4
- sage/algebras/orlik_terao.py +4 -4
- sage/algebras/steenrod/steenrod_algebra.py +37 -30
- sage/algebras/steenrod/steenrod_algebra_bases.py +2 -2
- sage/algebras/steenrod/steenrod_algebra_misc.py +4 -4
- sage/algebras/steenrod/steenrod_algebra_mult.py +2 -2
- sage/all__sagemath_modules.py +1 -0
- sage/calculus/integration.cpython-310-darwin.so +0 -0
- sage/calculus/integration.pyx +6 -5
- sage/calculus/interpolation.cpython-310-darwin.so +0 -0
- sage/calculus/interpolators.cpython-310-darwin.so +0 -0
- sage/calculus/ode.cpython-310-darwin.so +0 -0
- sage/calculus/ode.pxd +2 -2
- sage/calculus/ode.pyx +6 -4
- sage/calculus/riemann.cpython-310-darwin.so +0 -0
- sage/calculus/riemann.pyx +68 -48
- sage/calculus/transforms/dwt.cpython-310-darwin.so +0 -0
- sage/calculus/transforms/fft.cpython-310-darwin.so +0 -0
- sage/coding/ag_code_decoders.cpython-310-darwin.so +0 -0
- sage/coding/ag_code_decoders.pyx +31 -31
- sage/coding/binary_code.cpython-310-darwin.so +0 -0
- sage/coding/binary_code.pxd +6 -6
- sage/coding/binary_code.pyx +212 -173
- sage/coding/guruswami_sudan/utils.py +3 -5
- sage/coding/kasami_codes.cpython-310-darwin.so +0 -0
- sage/coding/kasami_codes.pyx +20 -24
- sage/coding/linear_code.py +2 -2
- sage/coding/linear_code_no_metric.py +5 -5
- sage/coding/linear_rank_metric.py +81 -19
- sage/combinat/cartesian_product.py +1 -1
- sage/combinat/free_module.py +22 -2
- sage/combinat/root_system/all.py +1 -1
- sage/combinat/root_system/ambient_space.py +1 -1
- sage/combinat/root_system/associahedron.py +4 -4
- sage/combinat/root_system/braid_move_calculator.py +2 -2
- sage/combinat/root_system/braid_orbit.cpython-310-darwin.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +1 -1
- sage/combinat/root_system/branching_rules.py +3 -3
- sage/combinat/root_system/cartan_type.py +14 -14
- sage/combinat/root_system/coxeter_group.py +3 -3
- sage/combinat/root_system/coxeter_matrix.py +1 -1
- sage/combinat/root_system/coxeter_type.py +12 -1
- sage/combinat/root_system/extended_affine_weyl_group.py +9 -9
- sage/combinat/root_system/fundamental_group.py +3 -5
- sage/combinat/root_system/hecke_algebra_representation.py +1 -1
- sage/combinat/root_system/integrable_representations.py +1 -1
- sage/combinat/root_system/pieri_factors.py +3 -3
- sage/combinat/root_system/root_lattice_realization_algebras.py +1 -1
- sage/combinat/root_system/root_lattice_realizations.py +1 -1
- sage/combinat/root_system/type_folded.py +3 -3
- sage/combinat/root_system/type_reducible.py +8 -7
- sage/combinat/root_system/type_super_A.py +2 -2
- sage/combinat/root_system/weight_lattice_realizations.py +9 -8
- sage/combinat/root_system/weyl_characters.py +2 -2
- sage/crypto/__init__.py +1 -0
- sage/crypto/block_cipher/des.py +1 -1
- sage/crypto/block_cipher/miniaes.py +3 -3
- sage/crypto/block_cipher/present.py +3 -3
- sage/crypto/block_cipher/sdes.py +3 -3
- sage/crypto/boolean_function.cpython-310-darwin.so +0 -0
- sage/crypto/boolean_function.pyx +22 -23
- sage/crypto/key_exchange/diffie_hellman.py +4 -9
- sage/crypto/mq/sr.py +1 -1
- sage/crypto/public_key/blum_goldwasser.py +3 -3
- sage/crypto/sbox.cpython-310-darwin.so +0 -0
- sage/crypto/sbox.pyx +1 -1
- sage/crypto/sboxes.py +22 -0
- sage/crypto/util.py +4 -6
- sage/ext/interpreters/__init__.py +1 -1
- sage/ext/interpreters/all__sagemath_modules.py +1 -1
- sage/ext/interpreters/wrapper_cc.cpython-310-darwin.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +5 -5
- sage/ext/interpreters/wrapper_cc.pyx +1 -1
- sage/ext/interpreters/wrapper_cdf.cpython-310-darwin.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +5 -7
- sage/ext/interpreters/wrapper_cdf.pyx +4 -10
- sage/ext/interpreters/wrapper_rdf.cpython-310-darwin.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +1 -1
- sage/ext/interpreters/wrapper_rdf.pyx +1 -1
- sage/ext/interpreters/wrapper_rr.cpython-310-darwin.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +5 -5
- sage/ext/interpreters/wrapper_rr.pyx +1 -2
- sage/geometry/toric_lattice.py +3 -3
- sage/geometry/toric_lattice_element.cpython-310-darwin.so +0 -0
- sage/groups/additive_abelian/additive_abelian_group.py +1 -1
- sage/groups/additive_abelian/qmodnz.py +4 -4
- sage/groups/matrix_gps/coxeter_group.py +17 -4
- sage/groups/matrix_gps/group_element.cpython-310-darwin.so +0 -0
- sage/groups/misc_gps/argument_groups.py +2 -2
- sage/groups/misc_gps/imaginary_groups.py +4 -4
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-310-darwin.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-310-darwin.so +0 -0
- sage/homology/chain_complex.py +0 -2
- sage/homology/hochschild_complex.py +3 -3
- sage/homology/homology_morphism.py +6 -6
- sage/homology/homology_vector_space_with_basis.py +1 -1
- sage/libs/gsl/array.cpython-310-darwin.so +0 -0
- sage/libs/mpmath/utils.cpython-310-darwin.so +0 -0
- sage/matrix/action.cpython-310-darwin.so +0 -0
- sage/matrix/args.cpython-310-darwin.so +0 -0
- sage/matrix/args.pyx +25 -10
- sage/matrix/benchmark.py +8 -4
- sage/matrix/compute_J_ideal.py +2 -2
- sage/matrix/constructor.cpython-310-darwin.so +0 -0
- sage/matrix/echelon_matrix.cpython-310-darwin.so +0 -0
- sage/matrix/echelon_matrix.pyx +1 -1
- sage/matrix/matrix0.cpython-310-darwin.so +0 -0
- sage/matrix/matrix0.pxd +3 -3
- sage/matrix/matrix0.pyx +7 -5
- sage/matrix/matrix1.cpython-310-darwin.so +0 -0
- sage/matrix/matrix1.pyx +87 -48
- sage/matrix/matrix2.cpython-310-darwin.so +0 -0
- sage/matrix/matrix2.pxd +3 -3
- sage/matrix/matrix2.pyx +1261 -63
- sage/matrix/matrix_cdv.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_complex_double_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_complex_double_dense.pyx +1 -1
- sage/matrix/matrix_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_dense.pyx +2 -3
- sage/matrix/matrix_double_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_double_dense.pyx +11 -5
- sage/matrix/matrix_double_sparse.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_generic_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_generic_sparse.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_generic_sparse.pyx +1 -1
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_numpy_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_polynomial_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_polynomial_dense.pyx +952 -261
- sage/matrix/matrix_real_double_dense.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_sparse.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_sparse.pyx +6 -7
- sage/matrix/matrix_window.cpython-310-darwin.so +0 -0
- sage/matrix/matrix_window.pyx +2 -2
- sage/matrix/misc_mpfr.cpython-310-darwin.so +0 -0
- sage/matrix/operation_table.py +0 -2
- sage/matrix/special.py +5 -1
- sage/matrix/strassen.cpython-310-darwin.so +0 -0
- sage/matrix/strassen.pyx +1 -1
- sage/matroids/basis_exchange_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/basis_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/chow_ring.py +68 -65
- sage/matroids/chow_ring_ideal.py +41 -38
- sage/matroids/circuit_closures_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/circuits_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/database_matroids.py +16 -5
- sage/matroids/dual_matroid.py +2 -2
- sage/matroids/extension.cpython-310-darwin.so +0 -0
- sage/matroids/flats_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/gammoid.py +1 -1
- sage/matroids/graphic_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/graphic_matroid.pyx +3 -3
- sage/matroids/lean_matrix.cpython-310-darwin.so +0 -0
- sage/matroids/lean_matrix.pyx +22 -22
- sage/matroids/linear_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/linear_matroid.pyx +13 -13
- sage/matroids/matroid.cpython-310-darwin.so +0 -0
- sage/matroids/matroid.pyx +15 -15
- sage/matroids/matroids_plot_helpers.py +48 -46
- sage/matroids/minor_matroid.py +2 -2
- sage/matroids/set_system.cpython-310-darwin.so +0 -0
- sage/matroids/transversal_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/transversal_matroid.pyx +3 -3
- sage/matroids/union_matroid.cpython-310-darwin.so +0 -0
- sage/matroids/union_matroid.pyx +3 -0
- sage/matroids/unpickling.cpython-310-darwin.so +0 -0
- sage/matroids/utilities.py +2 -2
- sage/misc/c3.cpython-310-darwin.so +0 -0
- sage/misc/compat.py +1 -2
- sage/misc/pickle_old.cpython-310-darwin.so +0 -0
- sage/modules/diamond_cutting.py +117 -30
- sage/modules/fg_pid/fgp_module.py +3 -3
- sage/modules/filtered_vector_space.py +4 -4
- sage/modules/finite_submodule_iter.cpython-310-darwin.so +0 -0
- sage/modules/fp_graded/free_module.py +2 -2
- sage/modules/fp_graded/module.py +2 -2
- sage/modules/fp_graded/morphism.py +4 -4
- sage/modules/fp_graded/steenrod/morphism.py +1 -1
- sage/modules/free_module.py +162 -26
- sage/modules/free_module_element.cpython-310-darwin.so +0 -0
- sage/modules/free_module_element.pyx +4 -4
- sage/modules/free_module_integer.py +2 -2
- sage/modules/free_module_morphism.py +3 -3
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +24 -13
- sage/modules/matrix_morphism.py +9 -9
- sage/modules/multi_filtered_vector_space.py +4 -4
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +11 -1
- sage/modules/submodule.py +1 -1
- sage/modules/torsion_quadratic_module.py +1 -1
- sage/modules/vector_complex_double_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_double_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_integer_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_integer_sparse.cpython-310-darwin.so +0 -0
- sage/modules/vector_integer_sparse.pyx +4 -4
- sage/modules/vector_modn_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_modn_sparse.cpython-310-darwin.so +0 -0
- sage/modules/vector_numpy_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_numpy_integer_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_rational_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_rational_dense.pyx +1 -1
- sage/modules/vector_rational_sparse.cpython-310-darwin.so +0 -0
- sage/modules/vector_rational_sparse.pyx +5 -5
- sage/modules/vector_real_double_dense.cpython-310-darwin.so +0 -0
- sage/modules/vector_space_morphism.py +2 -2
- sage/modules/with_basis/cell_module.py +17 -0
- sage/modules/with_basis/indexed_element.cpython-310-darwin.so +0 -0
- sage/modules/with_basis/indexed_element.pyx +1 -1
- sage/modules/with_basis/invariant.py +1 -1
- sage/modules/with_basis/representation.py +0 -1
- sage/modules/with_basis/subquotient.py +2 -2
- sage/numerical/gauss_legendre.cpython-310-darwin.so +0 -0
- sage/probability/probability_distribution.cpython-310-darwin.so +0 -0
- sage/quadratic_forms/binary_qf.py +11 -11
- sage/quadratic_forms/bqf_class_group.py +26 -92
- sage/quadratic_forms/count_local_2.cpython-310-darwin.so +0 -0
- sage/quadratic_forms/extras.py +1 -1
- sage/quadratic_forms/quadratic_form.py +5 -4
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +7 -4
- sage/quadratic_forms/quadratic_form__evaluate.cpython-310-darwin.so +0 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +10 -10
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +2 -2
- sage/quadratic_forms/ternary.cpython-310-darwin.so +0 -0
- sage/quadratic_forms/ternary_qf.py +50 -83
- sage/rings/cfinite_sequence.py +16 -17
- sage/rings/complex_conversion.cpython-310-darwin.so +0 -0
- sage/rings/complex_double.cpython-310-darwin.so +0 -0
- sage/rings/complex_double.pxd +1 -0
- sage/rings/complex_double.pyx +37 -32
- sage/rings/complex_mpc.cpython-310-darwin.so +0 -0
- sage/rings/complex_mpc.pyx +27 -23
- sage/rings/complex_mpfr.cpython-310-darwin.so +0 -0
- sage/rings/complex_mpfr.pyx +11 -11
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +277 -21
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +10 -1
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1 -1
- sage/rings/function_field/drinfeld_modules/homset.py +1 -2
- sage/rings/function_field/drinfeld_modules/morphism.py +2 -2
- sage/rings/function_field/hermite_form_polynomial.cpython-310-darwin.so +0 -0
- sage/rings/function_field/khuri_makdisi.cpython-310-darwin.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +27 -25
- sage/rings/invariants/invariant_theory.py +61 -60
- sage/rings/invariants/reconstruction.py +8 -8
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-310-darwin.so +0 -0
- sage/rings/polynomial/ore_function_element.py +1 -1
- sage/rings/polynomial/ore_polynomial_element.cpython-310-darwin.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +8 -8
- sage/rings/polynomial/ore_polynomial_ring.py +134 -17
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-310-darwin.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-310-darwin.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-310-darwin.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +3 -4
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-310-darwin.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +2 -5
- sage/rings/real_double_element_gsl.cpython-310-darwin.so +0 -0
- sage/rings/real_mpfr.cpython-310-darwin.so +0 -0
- sage/rings/real_mpfr.pyx +25 -7
- sage/rings/ring_extension.cpython-310-darwin.so +0 -0
- sage/rings/ring_extension.pyx +4 -2
- sage/rings/ring_extension_conversion.cpython-310-darwin.so +0 -0
- sage/rings/ring_extension_element.cpython-310-darwin.so +0 -0
- sage/rings/ring_extension_element.pyx +42 -0
- sage/rings/ring_extension_morphism.cpython-310-darwin.so +0 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/basic_stats.py +17 -15
- sage/stats/distributions/dgs_misc.h +11 -4
- sage/stats/distributions/discrete_gaussian_integer.cpython-310-darwin.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +9 -7
- sage/stats/hmm/chmm.cpython-310-darwin.so +0 -0
- sage/stats/hmm/chmm.pyx +13 -13
- sage/stats/hmm/distributions.cpython-310-darwin.so +0 -0
- sage/stats/hmm/distributions.pxd +3 -3
- sage/stats/hmm/distributions.pyx +3 -3
- sage/stats/hmm/hmm.cpython-310-darwin.so +0 -0
- sage/stats/hmm/hmm.pxd +3 -3
- sage/stats/hmm/hmm.pyx +6 -6
- sage/stats/hmm/util.cpython-310-darwin.so +0 -0
- sage/stats/hmm/util.pyx +6 -6
- sage/stats/intlist.cpython-310-darwin.so +0 -0
- sage/stats/intlist.pxd +3 -3
- sage/stats/time_series.cpython-310-darwin.so +0 -0
- sage/tensor/modules/alternating_contr_tensor.py +3 -3
- sage/tensor/modules/comp.py +3 -3
- sage/tensor/modules/ext_pow_free_module.py +3 -3
- sage/tensor/modules/format_utilities.py +3 -3
- sage/tensor/modules/free_module_linear_group.py +3 -3
- sage/tensor/modules/free_module_morphism.py +0 -1
- sage/tensor/modules/tensor_free_module.py +3 -3
- sage/tensor/modules/tensor_free_submodule.py +1 -1
- sage/tensor/modules/tensor_free_submodule_basis.py +1 -1
- sage/tensor/modules/tensor_with_indices.py +5 -5
- passagemath_modules.dylibs/libopenblas_armv8p-r0.3.28.dylib +0 -0
- {passagemath_modules-10.5.32.dist-info → passagemath_modules-10.6.20.dist-info}/top_level.txt +0 -0
sage/matrix/matrix2.pyx
CHANGED
|
@@ -1310,7 +1310,7 @@ cdef class Matrix(Matrix1):
|
|
|
1310
1310
|
|
|
1311
1311
|
Non-commutative rings behave as expected. These are the usual quaternions. ::
|
|
1312
1312
|
|
|
1313
|
-
sage: # needs sage.combinat
|
|
1313
|
+
sage: # needs sage.combinat sage.libs.singular
|
|
1314
1314
|
sage: R.<i,j,k> = QuaternionAlgebra(-1, -1)
|
|
1315
1315
|
sage: A = matrix(R, 2, [1,i,j,k])
|
|
1316
1316
|
sage: B = matrix(R, 2, [i,i,i,i])
|
|
@@ -1545,13 +1545,11 @@ cdef class Matrix(Matrix1):
|
|
|
1545
1545
|
m = self._nrows
|
|
1546
1546
|
n = self._ncols
|
|
1547
1547
|
if not m <= n:
|
|
1548
|
-
raise ValueError("must have m <= n, but m (
|
|
1548
|
+
raise ValueError(f"must have m <= n, but m (={m}) and n (={n})")
|
|
1549
1549
|
|
|
1550
1550
|
for r from 1 <= r < m+1:
|
|
1551
1551
|
lst = _choose(n, r)
|
|
1552
|
-
tmp = []
|
|
1553
|
-
for cols in lst:
|
|
1554
|
-
tmp.append(self.prod_of_row_sums(cols))
|
|
1552
|
+
tmp = [self.prod_of_row_sums(cols) for cols in lst]
|
|
1555
1553
|
s = sum(tmp)
|
|
1556
1554
|
# sn = (-1)^(m-r)
|
|
1557
1555
|
if (m - r) % 2 == 0:
|
|
@@ -1889,7 +1887,7 @@ cdef class Matrix(Matrix1):
|
|
|
1889
1887
|
|
|
1890
1888
|
The number of derangements of length `n` is the permanent
|
|
1891
1889
|
of a matrix with 0 on the diagonal and 1 elsewhere;
|
|
1892
|
-
for `n=21` it is `18795307255050944540` (see :oeis:`A000166`)
|
|
1890
|
+
for `n=21` it is `18795307255050944540` (see :oeis:`A000166`)::
|
|
1893
1891
|
|
|
1894
1892
|
sage: A = identity_matrix(21)
|
|
1895
1893
|
sage: A.rook_vector(complement=True)[-1]
|
|
@@ -3291,6 +3289,16 @@ cdef class Matrix(Matrix1):
|
|
|
3291
3289
|
sage: A._charpoly_df()
|
|
3292
3290
|
x^3 + 8*x^2 + 10*x + 1
|
|
3293
3291
|
|
|
3292
|
+
.. NOTE::
|
|
3293
|
+
|
|
3294
|
+
The key feature of this implementation is that it is division-free.
|
|
3295
|
+
This means that it can be used as a generic implementation for any
|
|
3296
|
+
ring (commutative and with multiplicative identity). The algorithm
|
|
3297
|
+
is described in full detail as Algorithm 3.1 in [Sei2002]_.
|
|
3298
|
+
|
|
3299
|
+
Note that there is a missing minus sign in front of the last term in
|
|
3300
|
+
the penultimate line of Algorithm 3.1.
|
|
3301
|
+
|
|
3294
3302
|
TESTS::
|
|
3295
3303
|
|
|
3296
3304
|
sage: A = matrix(ZZ, 0, 0)
|
|
@@ -3309,15 +3317,11 @@ cdef class Matrix(Matrix1):
|
|
|
3309
3317
|
sage: matrix(4, 4, lambda i, j: R.an_element())._charpoly_df() # needs sage.combinat
|
|
3310
3318
|
B[1]*x^4 - 4*B[u]*x^3
|
|
3311
3319
|
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
The key feature of this implementation is that it is division-free.
|
|
3315
|
-
This means that it can be used as a generic implementation for any
|
|
3316
|
-
ring (commutative and with multiplicative identity). The algorithm
|
|
3317
|
-
is described in full detail as Algorithm 3.1 in [Sei2002]_.
|
|
3320
|
+
Test that the function is interruptible::
|
|
3318
3321
|
|
|
3319
|
-
|
|
3320
|
-
|
|
3322
|
+
sage: m = matrix.random(RR, 128)
|
|
3323
|
+
sage: from sage.doctest.util import ensure_interruptible_after
|
|
3324
|
+
sage: with ensure_interruptible_after(1): m.charpoly()
|
|
3321
3325
|
"""
|
|
3322
3326
|
|
|
3323
3327
|
# Validate assertions
|
|
@@ -3374,6 +3378,7 @@ cdef class Matrix(Matrix1):
|
|
|
3374
3378
|
for j in range(t+1):
|
|
3375
3379
|
s = s + M.get_unsafe(i, j) * a.get_unsafe(p-1, j)
|
|
3376
3380
|
a.set_unsafe(p, i, s)
|
|
3381
|
+
sig_check()
|
|
3377
3382
|
|
|
3378
3383
|
# Set A[p, t] to be the (t)th entry in a[p, t]
|
|
3379
3384
|
A[p] = a.get_unsafe(p, t)
|
|
@@ -3480,10 +3485,17 @@ cdef class Matrix(Matrix1):
|
|
|
3480
3485
|
raise TypeError("lcm function not defined for elements of the base ring")
|
|
3481
3486
|
return d
|
|
3482
3487
|
|
|
3483
|
-
def diagonal(self):
|
|
3488
|
+
def diagonal(self, offset=0):
|
|
3484
3489
|
r"""
|
|
3485
3490
|
Return the diagonal entries of ``self``.
|
|
3486
3491
|
|
|
3492
|
+
INPUT:
|
|
3493
|
+
|
|
3494
|
+
- ``offset`` -- integer (default: ``0``); parameter pointing diagonal
|
|
3495
|
+
parallel to the main diagonal. The main diagonal is the one with
|
|
3496
|
+
offset 0. The diagonals above have positive offsets and the diagonals
|
|
3497
|
+
below have negative offsets.
|
|
3498
|
+
|
|
3487
3499
|
OUTPUT:
|
|
3488
3500
|
|
|
3489
3501
|
A list containing the entries of the matrix that
|
|
@@ -3506,6 +3518,16 @@ cdef class Matrix(Matrix1):
|
|
|
3506
3518
|
[14 15 16 17 18 19 20]
|
|
3507
3519
|
sage: B.diagonal()
|
|
3508
3520
|
[0, 8, 16]
|
|
3521
|
+
sage: B.diagonal(1)
|
|
3522
|
+
[1, 9, 17]
|
|
3523
|
+
sage: B.diagonal(-1)
|
|
3524
|
+
[7, 15]
|
|
3525
|
+
sage: B.diagonal(-2)
|
|
3526
|
+
[14]
|
|
3527
|
+
sage: B.diagonal(100) # when idx out of range
|
|
3528
|
+
[]
|
|
3529
|
+
sage: B.diagonal(-100)
|
|
3530
|
+
[]
|
|
3509
3531
|
|
|
3510
3532
|
sage: C = matrix(3, 2, range(6)); C
|
|
3511
3533
|
[0 1]
|
|
@@ -3513,6 +3535,10 @@ cdef class Matrix(Matrix1):
|
|
|
3513
3535
|
[4 5]
|
|
3514
3536
|
sage: C.diagonal()
|
|
3515
3537
|
[0, 3]
|
|
3538
|
+
sage: C.diagonal(-1)
|
|
3539
|
+
[2, 5]
|
|
3540
|
+
sage: C.diagonal(1)
|
|
3541
|
+
[1]
|
|
3516
3542
|
|
|
3517
3543
|
Empty matrices behave properly. ::
|
|
3518
3544
|
|
|
@@ -3521,8 +3547,11 @@ cdef class Matrix(Matrix1):
|
|
|
3521
3547
|
sage: E.diagonal()
|
|
3522
3548
|
[]
|
|
3523
3549
|
"""
|
|
3524
|
-
|
|
3525
|
-
|
|
3550
|
+
if offset >= 0:
|
|
3551
|
+
n = min(self.nrows(), self.ncols() - offset)
|
|
3552
|
+
return [self[i, i + offset] for i in range(n)]
|
|
3553
|
+
n = min(self.nrows() + offset, self.ncols())
|
|
3554
|
+
return [self[i - offset, i] for i in range(n)]
|
|
3526
3555
|
|
|
3527
3556
|
def trace(self):
|
|
3528
3557
|
"""
|
|
@@ -3579,6 +3608,42 @@ cdef class Matrix(Matrix1):
|
|
|
3579
3608
|
s += self.get_unsafe(i, j) * other.get_unsafe(j, i)
|
|
3580
3609
|
return s
|
|
3581
3610
|
|
|
3611
|
+
def get_bandwidth(self):
|
|
3612
|
+
"""
|
|
3613
|
+
Return the bandwidth of ``self``, which is the maximum `i` such that
|
|
3614
|
+
the `i` superdiagonal or subdiagonal contains a nonzero entry.
|
|
3615
|
+
|
|
3616
|
+
EXAMPLES::
|
|
3617
|
+
|
|
3618
|
+
sage: A = matrix([[1,0,0],[0,1,0],[0,0,1]]); A
|
|
3619
|
+
[1 0 0]
|
|
3620
|
+
[0 1 0]
|
|
3621
|
+
[0 0 1]
|
|
3622
|
+
sage: A.get_bandwidth()
|
|
3623
|
+
0
|
|
3624
|
+
|
|
3625
|
+
sage: B = matrix([[1,2,3],[0,4,5],[0,0,6]]); B
|
|
3626
|
+
[1 2 3]
|
|
3627
|
+
[0 4 5]
|
|
3628
|
+
[0 0 6]
|
|
3629
|
+
sage: B.get_bandwidth()
|
|
3630
|
+
2
|
|
3631
|
+
|
|
3632
|
+
sage: C = matrix(3, 2, range(6)); C
|
|
3633
|
+
[0 1]
|
|
3634
|
+
[2 3]
|
|
3635
|
+
[4 5]
|
|
3636
|
+
sage: C.get_bandwidth()
|
|
3637
|
+
2
|
|
3638
|
+
"""
|
|
3639
|
+
cdef Py_ssize_t i
|
|
3640
|
+
diag_range = max(self.nrows(), self.ncols()) - 1
|
|
3641
|
+
|
|
3642
|
+
for i in range(diag_range, 0, -1):
|
|
3643
|
+
if any(self.diagonal(i)) or any(self.diagonal(-i)):
|
|
3644
|
+
return ZZ(i)
|
|
3645
|
+
return ZZ.zero()
|
|
3646
|
+
|
|
3582
3647
|
#####################################################################################
|
|
3583
3648
|
# Generic Hessenberg Form and charpoly algorithm
|
|
3584
3649
|
#####################################################################################
|
|
@@ -3615,7 +3680,7 @@ cdef class Matrix(Matrix1):
|
|
|
3615
3680
|
H = self.change_ring(K)
|
|
3616
3681
|
H.hessenbergize()
|
|
3617
3682
|
except TypeError as msg:
|
|
3618
|
-
raise TypeError("%s\nHessenberg form only possible for matrices over a field"%msg)
|
|
3683
|
+
raise TypeError("%s\nHessenberg form only possible for matrices over a field" % msg)
|
|
3619
3684
|
else:
|
|
3620
3685
|
H = self.__copy__()
|
|
3621
3686
|
H.hessenbergize()
|
|
@@ -4596,6 +4661,7 @@ cdef class Matrix(Matrix1):
|
|
|
4596
4661
|
The "usual" quaternions are a non-commutative ring and computations
|
|
4597
4662
|
of kernels over these rings are not implemented. ::
|
|
4598
4663
|
|
|
4664
|
+
sage: # needs sage.libs.singular
|
|
4599
4665
|
sage: Q.<i,j,k> = QuaternionAlgebra(-1,-1)
|
|
4600
4666
|
sage: A = matrix(Q, 2, [i,j,-1,k])
|
|
4601
4667
|
sage: A.right_kernel_matrix()
|
|
@@ -5046,6 +5112,7 @@ cdef class Matrix(Matrix1):
|
|
|
5046
5112
|
Matrices over non-commutative rings are not a good idea either.
|
|
5047
5113
|
These are the "usual" quaternions. ::
|
|
5048
5114
|
|
|
5115
|
+
sage: # needs sage.libs.singular
|
|
5049
5116
|
sage: Q.<i,j,k> = QuaternionAlgebra(-1,-1)
|
|
5050
5117
|
sage: A = matrix(Q, 2, [i,j,-1,k])
|
|
5051
5118
|
sage: A.right_kernel()
|
|
@@ -5690,7 +5757,7 @@ cdef class Matrix(Matrix1):
|
|
|
5690
5757
|
return X, Y
|
|
5691
5758
|
return X
|
|
5692
5759
|
else:
|
|
5693
|
-
raise ValueError("no algorithm '%s'"%algorithm)
|
|
5760
|
+
raise ValueError("no algorithm '%s'" % algorithm)
|
|
5694
5761
|
|
|
5695
5762
|
def _decomposition_spin_generic(self, is_diagonalizable=False):
|
|
5696
5763
|
r"""
|
|
@@ -5753,14 +5820,16 @@ cdef class Matrix(Matrix1):
|
|
|
5753
5820
|
v = h.list()
|
|
5754
5821
|
|
|
5755
5822
|
while len(S) < tries:
|
|
5756
|
-
t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)),
|
|
5823
|
+
t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)),
|
|
5824
|
+
level=2, caller_name='generic spin decomp')
|
|
5757
5825
|
S.append(self.iterates(V.random_element(), num_iterates))
|
|
5758
|
-
verbose('done spinning',
|
|
5826
|
+
verbose('done spinning',
|
|
5827
|
+
level=2, t=t, caller_name='generic spin decomp')
|
|
5759
5828
|
|
|
5760
5829
|
for j in range(0 if W is None else W.nrows() // g.degree(), len(S)):
|
|
5761
5830
|
# Compute one element of the kernel of g(A)**m.
|
|
5762
|
-
t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),
|
|
5763
|
-
caller_name='generic spin decomp')
|
|
5831
|
+
t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(),
|
|
5832
|
+
level=2, caller_name='generic spin decomp')
|
|
5764
5833
|
w = S[j].linear_combination_of_rows(h.list())
|
|
5765
5834
|
t = verbose('done computing element of kernel of g(A)', t=t, level=2, caller_name='generic spin decomp')
|
|
5766
5835
|
|
|
@@ -5779,7 +5848,7 @@ cdef class Matrix(Matrix1):
|
|
|
5779
5848
|
verbose('computed row space', level=2, t=t, caller_name='generic spin decomp')
|
|
5780
5849
|
break
|
|
5781
5850
|
else:
|
|
5782
|
-
verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%(
|
|
5851
|
+
verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % (
|
|
5783
5852
|
W.rank(), m*g.degree()), level=2, caller_name='generic spin decomp')
|
|
5784
5853
|
tries += 1
|
|
5785
5854
|
if tries > 1000*m: # avoid an insanely long infinite loop
|
|
@@ -5815,12 +5884,13 @@ cdef class Matrix(Matrix1):
|
|
|
5815
5884
|
return decomp_seq([(V, m==1)])
|
|
5816
5885
|
F.sort()
|
|
5817
5886
|
for g, m in f.factor():
|
|
5818
|
-
t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s'%g.degree(), level=2)
|
|
5887
|
+
t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s' % g.degree(), level=2)
|
|
5819
5888
|
if is_diagonalizable:
|
|
5820
5889
|
B = g(self)
|
|
5821
5890
|
else:
|
|
5822
5891
|
B = g(self)
|
|
5823
|
-
t2 = verbose('decomposition -- raising g(self) to the power %s'%m,
|
|
5892
|
+
t2 = verbose('decomposition -- raising g(self) to the power %s' % m,
|
|
5893
|
+
level=2)
|
|
5824
5894
|
B = B ** m
|
|
5825
5895
|
verbose('done powering', level=2, t=t2)
|
|
5826
5896
|
t = verbose('decomposition -- done computing g(self)', level=2, t=t)
|
|
@@ -5911,7 +5981,7 @@ cdef class Matrix(Matrix1):
|
|
|
5911
5981
|
if not self.is_square():
|
|
5912
5982
|
raise ArithmeticError("self must be a square matrix")
|
|
5913
5983
|
if M.base_ring() != self.base_ring():
|
|
5914
|
-
raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s"%(
|
|
5984
|
+
raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s" % (
|
|
5915
5985
|
self.base_ring(), M.base_ring()))
|
|
5916
5986
|
if M.degree() != self.ncols():
|
|
5917
5987
|
raise ArithmeticError("M must be a subspace of an %s-dimensional space" % self.ncols())
|
|
@@ -5928,7 +5998,7 @@ cdef class Matrix(Matrix1):
|
|
|
5928
5998
|
sum_dim = sum([A.dimension() for A, _ in D])
|
|
5929
5999
|
assert sum_dim == M.dimension(), \
|
|
5930
6000
|
"bug in decomposition; " + \
|
|
5931
|
-
"the sum of the dimensions (=%s) of the factors must equal the dimension (%s) of the acted on space:\nFactors found: %s\nSpace: %s"%(sum_dim, M.dimension(), D, M)
|
|
6001
|
+
"the sum of the dimensions (=%s) of the factors must equal the dimension (%s) of the acted on space:\nFactors found: %s\nSpace: %s" % (sum_dim, M.dimension(), D, M)
|
|
5932
6002
|
|
|
5933
6003
|
# 3. Lift decomposition to subspaces of ambient vector space.
|
|
5934
6004
|
# Each basis vector for an element of D defines a linear
|
|
@@ -6475,12 +6545,22 @@ cdef class Matrix(Matrix1):
|
|
|
6475
6545
|
matrices with symbolic entries. ::
|
|
6476
6546
|
|
|
6477
6547
|
sage: A = matrix(QQ, 3, 3, range(9))
|
|
6478
|
-
sage: A.change_ring(RR).eigenspaces_left()
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
NotImplementedError: eigenspaces cannot be computed reliably
|
|
6482
|
-
for inexact rings such as Real Field with 53 bits of precision,
|
|
6548
|
+
sage: A.change_ring(RR).eigenspaces_left() # needs sage.rings.number_field
|
|
6549
|
+
doctest:warning...
|
|
6550
|
+
UserWarning: eigenspaces cannot be computed reliably for inexact rings such as Real Field with 53 bits of precision,
|
|
6483
6551
|
consult numerical or symbolic matrix classes for other options
|
|
6552
|
+
[(13.3484692283495,
|
|
6553
|
+
Vector space of degree 3 and dimension 0 over Real Field with 53 bits of precision
|
|
6554
|
+
User basis matrix:
|
|
6555
|
+
[]),
|
|
6556
|
+
(-0.000000000000000,
|
|
6557
|
+
Vector space of degree 3 and dimension 1 over Real Field with 53 bits of precision
|
|
6558
|
+
User basis matrix:
|
|
6559
|
+
[ 1.00000000000000 -2.00000000000000 1.00000000000000]),
|
|
6560
|
+
(-1.34846922834953,
|
|
6561
|
+
Vector space of degree 3 and dimension 0 over Real Field with 53 bits of precision
|
|
6562
|
+
User basis matrix:
|
|
6563
|
+
[])]
|
|
6484
6564
|
|
|
6485
6565
|
sage: # needs scipy
|
|
6486
6566
|
sage: em = A.change_ring(RDF).eigenmatrix_left()
|
|
@@ -6556,9 +6636,10 @@ cdef class Matrix(Matrix1):
|
|
|
6556
6636
|
msg = 'matrix must be square, not {0} x {1}'
|
|
6557
6637
|
raise TypeError(msg.format(self.nrows(), self.ncols()))
|
|
6558
6638
|
if not self.base_ring().is_exact():
|
|
6639
|
+
from warnings import warn
|
|
6559
6640
|
msg = ("eigenspaces cannot be computed reliably for inexact rings such as {0},\n",
|
|
6560
6641
|
"consult numerical or symbolic matrix classes for other options")
|
|
6561
|
-
|
|
6642
|
+
warn(''.join(msg).format(self.base_ring()))
|
|
6562
6643
|
|
|
6563
6644
|
format = self._eigenspace_format(format)
|
|
6564
6645
|
|
|
@@ -6830,13 +6911,21 @@ cdef class Matrix(Matrix1):
|
|
|
6830
6911
|
|
|
6831
6912
|
right_eigenspaces = eigenspaces_right
|
|
6832
6913
|
|
|
6833
|
-
def eigenvalues(self, extend=True):
|
|
6914
|
+
def eigenvalues(self, extend=True, algorithm=None) -> Sequence:
|
|
6834
6915
|
r"""
|
|
6835
6916
|
Return a sequence of the eigenvalues of a matrix, with
|
|
6836
6917
|
multiplicity. If the eigenvalues are roots of polynomials in ``QQ``,
|
|
6837
6918
|
then ``QQbar`` elements are returned that represent each separate
|
|
6838
6919
|
root.
|
|
6839
6920
|
|
|
6921
|
+
INPUT:
|
|
6922
|
+
|
|
6923
|
+
- ``extend`` -- (default: ``True``); see below
|
|
6924
|
+
- ``algorithm`` -- (default: ``None``); algorithm to use,
|
|
6925
|
+
supported values are ``'sage'``, ``'flint'``, ``'mpmath'``, ``'pari'``
|
|
6926
|
+
(passed to :meth:`eigenvectors_left`), or ``'pari_charpoly'``; if ``None``,
|
|
6927
|
+
the algorithm is chosen automatically
|
|
6928
|
+
|
|
6840
6929
|
If the option ``extend`` is set to ``False``, only eigenvalues in the base
|
|
6841
6930
|
ring are considered.
|
|
6842
6931
|
|
|
@@ -6927,6 +7016,96 @@ cdef class Matrix(Matrix1):
|
|
|
6927
7016
|
From: Finite Field in z3 of size 3^3
|
|
6928
7017
|
To: Algebraic closure of Finite Field of size 3
|
|
6929
7018
|
Defn: z3 |--> z3)
|
|
7019
|
+
|
|
7020
|
+
TESTS::
|
|
7021
|
+
|
|
7022
|
+
sage: import warnings
|
|
7023
|
+
sage: warnings.simplefilter("always")
|
|
7024
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7025
|
+
|
|
7026
|
+
Test different algorithms::
|
|
7027
|
+
|
|
7028
|
+
sage: m.eigenvalues(algorithm="sage") # needs sage.libs.pari
|
|
7029
|
+
doctest:warning...
|
|
7030
|
+
UserWarning: Using generic algorithm for an inexact ring,
|
|
7031
|
+
which will probably give incorrect results due to numerical precision issues.
|
|
7032
|
+
[-1.41421356237310*I, 1.41421356237310*I]
|
|
7033
|
+
sage: m.eigenvalues(algorithm="flint") # needs sage.libs.flint
|
|
7034
|
+
doctest:warning...
|
|
7035
|
+
FutureWarning: This class/method/function is marked as experimental.
|
|
7036
|
+
It, its functionality or its interface might change without a formal deprecation.
|
|
7037
|
+
See https://github.com/sagemath/sage/issues/30393 for details.
|
|
7038
|
+
[-1.41421356237309*I, 1.41421356237310*I]
|
|
7039
|
+
sage: m.eigenvalues(algorithm="mpmath") # abs tol 1e-14
|
|
7040
|
+
[-1.41421356237309*I, 1.41421356237309*I]
|
|
7041
|
+
sage: m.eigenvalues(algorithm="pari") # abs tol 1e-14 # needs sage.libs.pari
|
|
7042
|
+
[-1.4142135623730950487637880730318329370*I,
|
|
7043
|
+
1.4142135623730950487637880730318329370*I]
|
|
7044
|
+
sage: m.eigenvalues(algorithm="pari_charpoly") # abs tol 1e-14 # needs sage.libs.pari
|
|
7045
|
+
[-1.41421356237309505*I, 1.41421356237309505*I]
|
|
7046
|
+
sage: m.eigenvalues()
|
|
7047
|
+
[-1.41421356237309505*I, 1.41421356237309505*I]
|
|
7048
|
+
sage: type(m.eigenvalues())
|
|
7049
|
+
<class 'sage.structure.sequence.Sequence_generic'>
|
|
7050
|
+
"""
|
|
7051
|
+
if algorithm is None:
|
|
7052
|
+
from sage.rings.abc import RealField, ComplexField
|
|
7053
|
+
R = self.base_ring()
|
|
7054
|
+
if isinstance(R, (RealField, ComplexField)):
|
|
7055
|
+
algorithm = "pari_charpoly"
|
|
7056
|
+
else:
|
|
7057
|
+
algorithm = "sage"
|
|
7058
|
+
if algorithm == "sage":
|
|
7059
|
+
return self._eigenvalues_sage(extend=extend)
|
|
7060
|
+
elif algorithm == "pari_charpoly":
|
|
7061
|
+
from sage.libs.pari import pari
|
|
7062
|
+
return Sequence(pari(self).charpoly().polroots().sage())
|
|
7063
|
+
else:
|
|
7064
|
+
return self._eigenvectors_result_to_eigenvalues(
|
|
7065
|
+
self._eigenvectors_left(
|
|
7066
|
+
extend=extend, algorithm=algorithm,
|
|
7067
|
+
suppress_future_warning=False))
|
|
7068
|
+
|
|
7069
|
+
def _eigenvectors_result_to_eigenvalues(self, eigenvectors: list) -> Sequence:
|
|
7070
|
+
"""
|
|
7071
|
+
Convert the result of :meth:`eigenvectors_left` to a sequence of eigenvalues
|
|
7072
|
+
suitable to be returned by :meth:`eigenvalues`.
|
|
7073
|
+
|
|
7074
|
+
INPUT:
|
|
7075
|
+
|
|
7076
|
+
- ``eigenvectors`` -- a list of tuples of the form ``(e,V,n)``
|
|
7077
|
+
as returned by :meth:`eigenvectors_left`
|
|
7078
|
+
|
|
7079
|
+
OUTPUT: a :class:`Sequence` of eigenvalues
|
|
7080
|
+
|
|
7081
|
+
TESTS::
|
|
7082
|
+
|
|
7083
|
+
sage: # needs sage.rings.number_field
|
|
7084
|
+
sage: A = matrix(QQ, [[1, 2], [3, 4]])
|
|
7085
|
+
sage: l = A.eigenvectors_left(); l
|
|
7086
|
+
[(-0.3722813232690144?, [(1, -0.4574271077563382?)], 1),
|
|
7087
|
+
(5.372281323269015?, [(1, 1.457427107756339?)], 1)]
|
|
7088
|
+
sage: A._eigenvectors_result_to_eigenvalues(l)
|
|
7089
|
+
[-0.3722813232690144?, 5.372281323269015?]
|
|
7090
|
+
"""
|
|
7091
|
+
return Sequence([e for e, _, _ in eigenvectors])
|
|
7092
|
+
|
|
7093
|
+
def _eigenvalues_sage(self, extend=True) -> Sequence:
|
|
7094
|
+
"""
|
|
7095
|
+
Compute the eigenvalues of a matrix using algorithm implemented in Sage.
|
|
7096
|
+
|
|
7097
|
+
INPUT:
|
|
7098
|
+
|
|
7099
|
+
- ``extend`` -- boolean (default: ``True``)
|
|
7100
|
+
|
|
7101
|
+
TESTS::
|
|
7102
|
+
|
|
7103
|
+
sage: # needs sage.rings.number_field
|
|
7104
|
+
sage: A = matrix(QQ, [[1, 2], [3, 4]])
|
|
7105
|
+
sage: A.eigenvalues(algorithm="sage") # indirect doctest
|
|
7106
|
+
[-0.3722813232690144?, 5.372281323269015?]
|
|
7107
|
+
sage: A._eigenvalues_sage()
|
|
7108
|
+
[-0.3722813232690144?, 5.372281323269015?]
|
|
6930
7109
|
"""
|
|
6931
7110
|
x = self.fetch('eigenvalues')
|
|
6932
7111
|
if x is not None:
|
|
@@ -6966,7 +7145,7 @@ cdef class Matrix(Matrix1):
|
|
|
6966
7145
|
self.cache('eigenvalues', eigenvalues)
|
|
6967
7146
|
return eigenvalues
|
|
6968
7147
|
|
|
6969
|
-
def eigenvectors_left(self, other=None, *, extend=True):
|
|
7148
|
+
def eigenvectors_left(self, other=None, *, extend=True, algorithm=None) -> list:
|
|
6970
7149
|
r"""
|
|
6971
7150
|
Compute the left eigenvectors of a matrix.
|
|
6972
7151
|
|
|
@@ -6979,14 +7158,25 @@ cdef class Matrix(Matrix1):
|
|
|
6979
7158
|
|
|
6980
7159
|
- ``extend`` -- boolean (default: ``True``)
|
|
6981
7160
|
|
|
7161
|
+
- ``algorithm`` -- string (default: ``None``); if ``None``, then it is
|
|
7162
|
+
chosen automatically; options are:
|
|
7163
|
+
|
|
7164
|
+
* ``'sage'``
|
|
7165
|
+
* ``'flint'``
|
|
7166
|
+
* ``'mpmath'``
|
|
7167
|
+
* ``'pari'``
|
|
7168
|
+
* ``'scipy'`` - only supported for matrices over :class:`RDF <sage.rings.real_double.RealDoubleField_class>`
|
|
7169
|
+
and :class:`CDF <sage.rings.complex_double.ComplexDoubleField_class>`
|
|
7170
|
+
|
|
6982
7171
|
OUTPUT:
|
|
6983
7172
|
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
7173
|
+
Returns a list of tuples of the form ``(e,V,n)``,
|
|
7174
|
+
each tuple corresponds to a distinct eigenvalue,
|
|
7175
|
+
where ``e`` is the eigenvalue, ``V`` is a list of eigenvectors forming a
|
|
7176
|
+
basis for the corresponding left eigenspace, and ``n`` is the algebraic
|
|
6987
7177
|
multiplicity of the eigenvalue.
|
|
6988
7178
|
|
|
6989
|
-
If the option extend is set to False
|
|
7179
|
+
If the option ``extend`` is set to ``False``, then only the eigenvalues that
|
|
6990
7180
|
live in the base ring are considered.
|
|
6991
7181
|
|
|
6992
7182
|
EXAMPLES:
|
|
@@ -7042,6 +7232,22 @@ cdef class Matrix(Matrix1):
|
|
|
7042
7232
|
sage: K.<i> = QuadraticField(-1)
|
|
7043
7233
|
sage: m = matrix(K, 4, [2,4*i,-i,0, -4*i,2,-1,0, 2*i,-2,0,0, 4*i+4, 4*i-4,1-i,-2])
|
|
7044
7234
|
sage: assert all(m*v == e*v for e, vs, _ in m.eigenvectors_right() for v in vs)
|
|
7235
|
+
|
|
7236
|
+
The following currently uses ``algorithm="flint"`` under the hood,
|
|
7237
|
+
but ``FutureWarning`` must not be raised. This is because the internal
|
|
7238
|
+
implementation may change in the future to keep the external interface.
|
|
7239
|
+
|
|
7240
|
+
::
|
|
7241
|
+
|
|
7242
|
+
sage: # needs sage.libs.flint
|
|
7243
|
+
sage: import warnings
|
|
7244
|
+
sage: warnings.simplefilter("always")
|
|
7245
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7246
|
+
sage: m.eigenvectors_left()
|
|
7247
|
+
[(-1.41421356237309*I, [(-0.816496580927726, -0.577350269189626*I)], 1),
|
|
7248
|
+
(1.41421356237310*I, [(-0.866025403784438*I, -0.612372435695794)], 1)]
|
|
7249
|
+
sage: m.eigenvectors_left(extend=False)
|
|
7250
|
+
[]
|
|
7045
7251
|
"""
|
|
7046
7252
|
if other is not None:
|
|
7047
7253
|
if isinstance(other, bool):
|
|
@@ -7057,15 +7263,77 @@ cdef class Matrix(Matrix1):
|
|
|
7057
7263
|
'for RDF and CDF, but not for %s'
|
|
7058
7264
|
% self.base_ring())
|
|
7059
7265
|
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7266
|
+
if algorithm is None:
|
|
7267
|
+
R = self.base_ring()
|
|
7268
|
+
from sage.rings.abc import RealField, ComplexField
|
|
7269
|
+
if isinstance(R, (RealField, ComplexField)):
|
|
7270
|
+
return self._eigenvectors_left(
|
|
7271
|
+
other, extend=extend, algorithm='flint', suppress_future_warning=True)
|
|
7272
|
+
else:
|
|
7273
|
+
algorithm = 'sage'
|
|
7274
|
+
return self._eigenvectors_left(
|
|
7275
|
+
other, extend=extend, algorithm=algorithm, suppress_future_warning=False)
|
|
7276
|
+
|
|
7277
|
+
def _eigenvectors_left(self, other=None, *, extend: bool, algorithm: str,
|
|
7278
|
+
suppress_future_warning: bool) -> list:
|
|
7279
|
+
"""
|
|
7280
|
+
Do the same thing as :meth:`eigenvectors_left`, but ``algorithm``
|
|
7281
|
+
cannot be ``None``, and ``suppress_future_warning`` is provided
|
|
7282
|
+
to suppress the ``FutureWarning`` raised by the flint method.
|
|
7283
|
+
|
|
7284
|
+
TESTS::
|
|
7063
7285
|
|
|
7286
|
+
sage: # needs sage.libs.flint
|
|
7287
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7288
|
+
sage: m._eigenvectors_left(extend=False, algorithm="flint", suppress_future_warning=True)
|
|
7289
|
+
[]
|
|
7290
|
+
"""
|
|
7291
|
+
if algorithm == 'sage':
|
|
7292
|
+
return self._eigenvectors_left_sage(extend=extend)
|
|
7293
|
+
elif algorithm == 'flint':
|
|
7294
|
+
return self._fix_eigenvectors_extend(self._eigenvectors_left_flint(suppress_future_warning), extend)
|
|
7295
|
+
elif algorithm == 'mpmath':
|
|
7296
|
+
return self._fix_eigenvectors_extend(self._eigenvectors_left_mpmath(), extend)
|
|
7297
|
+
elif algorithm == 'pari':
|
|
7298
|
+
return self._fix_eigenvectors_extend(self._eigenvectors_left_pari(), extend)
|
|
7299
|
+
else:
|
|
7300
|
+
raise ValueError('algorithm value not recognized')
|
|
7301
|
+
|
|
7302
|
+
def _eigenvectors_left_sage(self, *, extend=True) -> list:
|
|
7303
|
+
"""
|
|
7304
|
+
Compute the left eigenvectors of a matrix
|
|
7305
|
+
using a generic algorithm implemented in Sage.
|
|
7306
|
+
|
|
7307
|
+
INPUT:
|
|
7308
|
+
|
|
7309
|
+
- ``extend`` -- boolean (default: ``True``)
|
|
7310
|
+
|
|
7311
|
+
OUTPUT:
|
|
7312
|
+
|
|
7313
|
+
See :meth:`eigenvectors_left`.
|
|
7314
|
+
|
|
7315
|
+
TESTS::
|
|
7316
|
+
|
|
7317
|
+
sage: # needs sage.rings.number_field
|
|
7318
|
+
sage: import warnings
|
|
7319
|
+
sage: warnings.simplefilter("always")
|
|
7320
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7321
|
+
sage: m.eigenvectors_left(algorithm="sage")
|
|
7322
|
+
doctest:warning...
|
|
7323
|
+
UserWarning: eigenspaces cannot be computed reliably for inexact rings such as Real Field with 53 bits of precision,
|
|
7324
|
+
consult numerical or symbolic matrix classes for other options
|
|
7325
|
+
[(-1.41421356237310*I, [(1.00000000000000, 0.707106781186548*I)], 1),
|
|
7326
|
+
(1.41421356237310*I, [(1.00000000000000, -0.707106781186548*I)], 1)]
|
|
7327
|
+
sage: m.eigenvectors_left(algorithm="sage", extend=False)
|
|
7328
|
+
doctest:warning...
|
|
7329
|
+
UserWarning: eigenspaces cannot be computed reliably for inexact rings such as Real Field with 53 bits of precision,
|
|
7330
|
+
consult numerical or symbolic matrix classes for other options
|
|
7331
|
+
[]
|
|
7332
|
+
"""
|
|
7064
7333
|
if not self.base_ring().is_exact():
|
|
7065
7334
|
from warnings import warn
|
|
7066
7335
|
warn("Using generic algorithm for an inexact ring, which may result in garbage from numerical precision issues.")
|
|
7067
7336
|
|
|
7068
|
-
from sage.categories.homset import hom
|
|
7069
7337
|
eigenspaces = self.eigenspaces_left(format='galois', algebraic_multiplicity=True)
|
|
7070
7338
|
evec_list = []
|
|
7071
7339
|
n = self._nrows
|
|
@@ -7079,20 +7347,169 @@ cdef class Matrix(Matrix1):
|
|
|
7079
7347
|
if eigval.parent().fraction_field() == F:
|
|
7080
7348
|
evec_eval_list.append((eigval, eigbasis, eigmult))
|
|
7081
7349
|
else:
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7350
|
+
from sage.categories.homset import Hom
|
|
7351
|
+
from sage.rings.abc import RealField
|
|
7352
|
+
if isinstance(self.base_ring(), RealField):
|
|
7353
|
+
# then eigval is an element of RR[x]/f(x)
|
|
7354
|
+
# find all morphism of that ring into CC
|
|
7355
|
+
f = eigval.parent().modulus()
|
|
7356
|
+
rs = f.roots(self.base_ring().complex_field(), multiplicities=False)
|
|
7357
|
+
g = eigval.lift()
|
|
7358
|
+
eigval_conj = [g(r) for r in rs]
|
|
7359
|
+
else:
|
|
7360
|
+
try:
|
|
7361
|
+
from sage.rings.qqbar import QQbar
|
|
7362
|
+
eigval_conj = eigval.galois_conjugates(QQbar)
|
|
7363
|
+
except AttributeError:
|
|
7364
|
+
raise NotImplementedError("eigenvectors are not implemented for matrices with eigenvalues that are not in the fraction field of the base ring or in QQbar")
|
|
7087
7365
|
|
|
7088
7366
|
for e in eigval_conj:
|
|
7089
|
-
m =
|
|
7367
|
+
m = Hom(eigval.parent(), e.parent())(e, check=False)
|
|
7368
|
+
# check=False because the base_ring may not be exact
|
|
7090
7369
|
space = (e.parent())**n
|
|
7091
7370
|
evec_list = [(space)([m(i) for i in v]) for v in eigbasis]
|
|
7092
7371
|
evec_eval_list.append((e, evec_list, eigmult))
|
|
7093
7372
|
|
|
7094
7373
|
return evec_eval_list
|
|
7095
7374
|
|
|
7375
|
+
def _fix_eigenvectors_extend(self, eigenvectors: list, extend: bool) -> list:
|
|
7376
|
+
"""
|
|
7377
|
+
Fix the eigenvectors if the extend option is set to ``False``.
|
|
7378
|
+
|
|
7379
|
+
INPUT:
|
|
7380
|
+
|
|
7381
|
+
- ``eigenvectors`` -- a list of tuples of the form ``(e,V,n)``
|
|
7382
|
+
as returned by :meth:`eigenvectors_left`
|
|
7383
|
+
- ``extend`` -- boolean
|
|
7384
|
+
|
|
7385
|
+
OUTPUT:
|
|
7386
|
+
|
|
7387
|
+
If ``extend`` is ``True``, return ``eigenvectors`` unchanged.
|
|
7388
|
+
Otherwise, return a new list with only the eigenvalues that live in the base ring.
|
|
7389
|
+
|
|
7390
|
+
TESTS::
|
|
7391
|
+
|
|
7392
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7393
|
+
sage: l = m.eigenvectors_left(algorithm="pari"); l # abs tol 1e-14 # needs sage.libs.pari
|
|
7394
|
+
[(-1.4142135623730950487637880730318329370*I,
|
|
7395
|
+
[(0.707106781186547524*I, 1.00000000000000000)],
|
|
7396
|
+
1),
|
|
7397
|
+
(1.4142135623730950487637880730318329370*I,
|
|
7398
|
+
[(-0.707106781186547524*I, 1.00000000000000000)],
|
|
7399
|
+
1)]
|
|
7400
|
+
sage: m._fix_eigenvectors_extend(l, extend=True) # abs tol 1e-14 # needs sage.libs.pari
|
|
7401
|
+
[(-1.4142135623730950487637880730318329370*I,
|
|
7402
|
+
[(0.707106781186547524*I, 1.00000000000000000)],
|
|
7403
|
+
1),
|
|
7404
|
+
(1.4142135623730950487637880730318329370*I,
|
|
7405
|
+
[(-0.707106781186547524*I, 1.00000000000000000)],
|
|
7406
|
+
1)]
|
|
7407
|
+
sage: m._fix_eigenvectors_extend(l, extend=False) # needs sage.libs.pari
|
|
7408
|
+
[]
|
|
7409
|
+
"""
|
|
7410
|
+
if extend:
|
|
7411
|
+
return eigenvectors
|
|
7412
|
+
R = self.base_ring()
|
|
7413
|
+
try:
|
|
7414
|
+
if R.algebraic_closure() is R:
|
|
7415
|
+
return eigenvectors
|
|
7416
|
+
except (AttributeError, NotImplementedError):
|
|
7417
|
+
pass
|
|
7418
|
+
return [(e, V, n) for e, V, n in eigenvectors if e in R]
|
|
7419
|
+
|
|
7420
|
+
def _eigenvectors_left_flint(self, suppress_future_warning: bool) -> list:
|
|
7421
|
+
"""
|
|
7422
|
+
Compute the left eigenvectors of a matrix
|
|
7423
|
+
using the FLINT library.
|
|
7424
|
+
|
|
7425
|
+
Only works for matrices over ``RealField`` or ``ComplexField``.
|
|
7426
|
+
|
|
7427
|
+
INPUT:
|
|
7428
|
+
|
|
7429
|
+
- ``suppress_future_warning`` -- boolean; whether to suppress
|
|
7430
|
+
the ``FutureWarning``
|
|
7431
|
+
|
|
7432
|
+
OUTPUT:
|
|
7433
|
+
|
|
7434
|
+
See :meth:`eigenvectors_left`.
|
|
7435
|
+
|
|
7436
|
+
TESTS:
|
|
7437
|
+
|
|
7438
|
+
This method is supposed to raise a ``FutureWarning`` but
|
|
7439
|
+
the implementation in :class:`sage.misc.superseded.experimental`
|
|
7440
|
+
only raises the warning at most once, because of doctest ordering
|
|
7441
|
+
the warning is not seen below. See :issue:`39811`. ::
|
|
7442
|
+
|
|
7443
|
+
sage: # needs sage.libs.flint
|
|
7444
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7445
|
+
sage: m.eigenvectors_left(algorithm="flint") # indirect doctest
|
|
7446
|
+
[(-1.41421356237309*I, [(-0.816496580927726, -0.577350269189626*I)], 1),
|
|
7447
|
+
(1.41421356237310*I, [(-0.866025403784438*I, -0.612372435695794)], 1)]
|
|
7448
|
+
sage: m.eigenvectors_left(algorithm="flint", extend=False)
|
|
7449
|
+
[]
|
|
7450
|
+
"""
|
|
7451
|
+
if suppress_future_warning:
|
|
7452
|
+
import warnings
|
|
7453
|
+
with warnings.catch_warnings():
|
|
7454
|
+
warnings.simplefilter("ignore", category=FutureWarning)
|
|
7455
|
+
result = self._eigenvectors_left_flint(False)
|
|
7456
|
+
return result
|
|
7457
|
+
from sage.rings.complex_arb import ComplexBallField
|
|
7458
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
7459
|
+
C = ComplexField(self.base_ring().precision())
|
|
7460
|
+
return [(C(e), [v.change_ring(C) for v in V], n) for e, V, n in
|
|
7461
|
+
self.change_ring(ComplexBallField(self.base_ring().precision())).eigenvectors_left()]
|
|
7462
|
+
|
|
7463
|
+
def _eigenvectors_left_mpmath(self) -> list:
|
|
7464
|
+
"""
|
|
7465
|
+
Compute the left eigenvectors of a matrix
|
|
7466
|
+
using ``mpmath``.
|
|
7467
|
+
|
|
7468
|
+
Only works for matrices over ``RealField`` or ``ComplexField``.
|
|
7469
|
+
|
|
7470
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7471
|
+
sage: m.eigenvectors_left(algorithm="mpmath")
|
|
7472
|
+
[(-1.41421356237309*I, [(-0.866025403784439, -0.612372435695794*I)], 1),
|
|
7473
|
+
(1.41421356237309*I, [(-0.816496580927726*I, -0.577350269189626)], 1)]
|
|
7474
|
+
sage: m.eigenvectors_left(algorithm="mpmath", extend=False)
|
|
7475
|
+
[]
|
|
7476
|
+
"""
|
|
7477
|
+
from mpmath import mp
|
|
7478
|
+
eigenvalues, eigenvectors = mp.eig(self._mpmath_(), left=True, right=False)
|
|
7479
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
7480
|
+
C = ComplexField(self.base_ring().precision())
|
|
7481
|
+
from sage.modules.free_module_element import vector
|
|
7482
|
+
return [
|
|
7483
|
+
(C(e), [vector(C, V)], 1)
|
|
7484
|
+
for e, V in zip(eigenvalues, eigenvectors.tolist())
|
|
7485
|
+
]
|
|
7486
|
+
|
|
7487
|
+
def _eigenvectors_left_pari(self) -> list:
|
|
7488
|
+
"""
|
|
7489
|
+
Compute the left eigenvectors of a matrix
|
|
7490
|
+
using the PARI library.
|
|
7491
|
+
|
|
7492
|
+
Only works for matrices over ``RealField`` or ``ComplexField``.
|
|
7493
|
+
|
|
7494
|
+
sage: # needs sage.libs.pari
|
|
7495
|
+
sage: m = matrix(RR, [[0, 1], [-2, 0]])
|
|
7496
|
+
sage: m.eigenvectors_left(algorithm="pari") # abs tol 1e-14
|
|
7497
|
+
[(-1.4142135623730950487637880730318329370*I,
|
|
7498
|
+
[(0.707106781186547524*I, 1.00000000000000000)],
|
|
7499
|
+
1),
|
|
7500
|
+
(1.4142135623730950487637880730318329370*I,
|
|
7501
|
+
[(-0.707106781186547524*I, 1.00000000000000000)],
|
|
7502
|
+
1)]
|
|
7503
|
+
sage: m.eigenvectors_left(algorithm="pari", extend=False)
|
|
7504
|
+
[]
|
|
7505
|
+
"""
|
|
7506
|
+
from sage.libs.pari import pari
|
|
7507
|
+
eigenvalues, eigenvectors = pari(self).mateigen(flag=1, precision=self.base_ring().precision()).sage()
|
|
7508
|
+
return [
|
|
7509
|
+
(e, [V], 1)
|
|
7510
|
+
for e, V in zip(eigenvalues, eigenvectors.columns())
|
|
7511
|
+
]
|
|
7512
|
+
|
|
7096
7513
|
left_eigenvectors = eigenvectors_left
|
|
7097
7514
|
|
|
7098
7515
|
def eigenvectors_right(self, other=None, *, extend=True):
|
|
@@ -7780,7 +8197,7 @@ cdef class Matrix(Matrix1):
|
|
|
7780
8197
|
try:
|
|
7781
8198
|
a, d, p = self._echelon_form_PID()
|
|
7782
8199
|
except TypeError as msg:
|
|
7783
|
-
raise NotImplementedError("%s\nechelon form over %s not yet implemented"%(msg, self.base_ring()))
|
|
8200
|
+
raise NotImplementedError("%s\nechelon form over %s not yet implemented" % (msg, self.base_ring()))
|
|
7784
8201
|
|
|
7785
8202
|
for c from 0 <= c < self.ncols():
|
|
7786
8203
|
for r from 0 <= r < self.nrows():
|
|
@@ -7984,7 +8401,7 @@ cdef class Matrix(Matrix1):
|
|
|
7984
8401
|
kwds['algorithm'] = algorithm
|
|
7985
8402
|
return self._echelonize_ring(**kwds)
|
|
7986
8403
|
except ArithmeticError as msg:
|
|
7987
|
-
raise NotImplementedError("%s\nEchelon form not implemented over '%s'."%(msg, basring))
|
|
8404
|
+
raise NotImplementedError("%s\nEchelon form not implemented over '%s'." % (msg, basring))
|
|
7988
8405
|
|
|
7989
8406
|
def echelon_form(self, algorithm='default', cutoff=0, **kwds):
|
|
7990
8407
|
r"""
|
|
@@ -8970,7 +9387,8 @@ cdef class Matrix(Matrix1):
|
|
|
8970
9387
|
[ 0 0 0 0]
|
|
8971
9388
|
[ 0 0 0 0]
|
|
8972
9389
|
"""
|
|
8973
|
-
tm = verbose('strassen echelon of %s x %s matrix'%(self._nrows, self._ncols),
|
|
9390
|
+
tm = verbose('strassen echelon of %s x %s matrix' % (self._nrows, self._ncols),
|
|
9391
|
+
level=2)
|
|
8974
9392
|
|
|
8975
9393
|
self.check_mutability()
|
|
8976
9394
|
|
|
@@ -9248,7 +9666,7 @@ cdef class Matrix(Matrix1):
|
|
|
9248
9666
|
"""
|
|
9249
9667
|
if self._subdivisions is None:
|
|
9250
9668
|
self._subdivisions = ([0, self._nrows], [0, self._ncols])
|
|
9251
|
-
key = "subdivision %s %s"%(i, j)
|
|
9669
|
+
key = "subdivision %s %s" % (i, j)
|
|
9252
9670
|
sd = self.fetch(key)
|
|
9253
9671
|
if sd is None:
|
|
9254
9672
|
sd = self[self._subdivisions[0][i]:self._subdivisions[0][i+1],
|
|
@@ -9296,10 +9714,10 @@ cdef class Matrix(Matrix1):
|
|
|
9296
9714
|
if not i and not j:
|
|
9297
9715
|
return self[x, y]
|
|
9298
9716
|
else:
|
|
9299
|
-
raise IndexError("No such submatrix %s, %s"%(i, j))
|
|
9717
|
+
raise IndexError("No such submatrix %s, %s" % (i, j))
|
|
9300
9718
|
if x >= self._subdivisions[0][i+1]-self._subdivisions[0][i] or \
|
|
9301
9719
|
y >= self._subdivisions[1][j+1]-self._subdivisions[1][j]:
|
|
9302
|
-
raise IndexError("Submatrix %s,%s has no entry %s,%s"%(i, j, x, y))
|
|
9720
|
+
raise IndexError("Submatrix %s,%s has no entry %s,%s" % (i, j, x, y))
|
|
9303
9721
|
return self[self._subdivisions[0][i] + x, self._subdivisions[1][j] + y]
|
|
9304
9722
|
|
|
9305
9723
|
def _subdivide_on_augment(self, left, right):
|
|
@@ -10246,7 +10664,7 @@ cdef class Matrix(Matrix1):
|
|
|
10246
10664
|
sage: a.density()
|
|
10247
10665
|
0
|
|
10248
10666
|
"""
|
|
10249
|
-
cdef
|
|
10667
|
+
cdef Py_ssize_t x, y, k
|
|
10250
10668
|
k = 0
|
|
10251
10669
|
nr = self.nrows()
|
|
10252
10670
|
nc = self.ncols()
|
|
@@ -10478,7 +10896,7 @@ cdef class Matrix(Matrix1):
|
|
|
10478
10896
|
raise ValueError("self must be a square matrix")
|
|
10479
10897
|
|
|
10480
10898
|
A = self.charpoly().shift(-1)(self)
|
|
10481
|
-
return A if n%2 else -A
|
|
10899
|
+
return A if n % 2 else -A
|
|
10482
10900
|
|
|
10483
10901
|
def QR(self, full=True):
|
|
10484
10902
|
r"""
|
|
@@ -12955,7 +13373,188 @@ cdef class Matrix(Matrix1):
|
|
|
12955
13373
|
else:
|
|
12956
13374
|
return subspace
|
|
12957
13375
|
|
|
12958
|
-
def
|
|
13376
|
+
def _cholesky_extended_ff(self):
|
|
13377
|
+
r"""
|
|
13378
|
+
Performs the extended Cholesky decomposition of a Hermitian matrix over a finite field of square order.
|
|
13379
|
+
|
|
13380
|
+
INPUT:
|
|
13381
|
+
|
|
13382
|
+
- ``self`` -- a square matrix with entries from a finite field of square order
|
|
13383
|
+
|
|
13384
|
+
.. SEEALSO::
|
|
13385
|
+
|
|
13386
|
+
:meth:`cholesky()`
|
|
13387
|
+
|
|
13388
|
+
OUTPUT:
|
|
13389
|
+
|
|
13390
|
+
For a Hermitian matrix `A` the routine returns a matrix `B` such that,
|
|
13391
|
+
|
|
13392
|
+
.. MATH::
|
|
13393
|
+
|
|
13394
|
+
A = B B^*,
|
|
13395
|
+
|
|
13396
|
+
where `B^*` is the conjugate-transpose.
|
|
13397
|
+
|
|
13398
|
+
ALGORITHM:
|
|
13399
|
+
|
|
13400
|
+
First, we ensure the matrix is square and defined over a finite field of square order. Then we can perform the conjugate-symmetric
|
|
13401
|
+
version of Gaussian elimination, but the resulting decomposition matrix `L` might not be lower triangular.
|
|
13402
|
+
|
|
13403
|
+
This is a translation of ``BaseChangeToCanonical`` from the GAP ``forms`` package (for a Hermitian form).
|
|
13404
|
+
|
|
13405
|
+
EXAMPLES:
|
|
13406
|
+
|
|
13407
|
+
Here we use the extended decomposition, where the result may not be a lower triangular matrix::
|
|
13408
|
+
|
|
13409
|
+
sage: # needs sage.rings.finite_rings
|
|
13410
|
+
sage: U = matrix(GF(17**2),[[0,1],[1,0]])
|
|
13411
|
+
sage: B = U._cholesky_extended_ff(); B
|
|
13412
|
+
[13*z2 + 6 3*z2 + 16]
|
|
13413
|
+
[13*z2 + 6 14*z2 + 1]
|
|
13414
|
+
sage: U == B * B.H
|
|
13415
|
+
True
|
|
13416
|
+
sage: U = matrix(GF(13**2),[[1,4,7],[4,1,4],[7,4,1]])
|
|
13417
|
+
sage: B = U._cholesky_extended_ff(); B
|
|
13418
|
+
[ 1 0 0]
|
|
13419
|
+
[ 4 7*z2 + 3 0]
|
|
13420
|
+
[ 7 6*z2 + 10 12*z2 + 6]
|
|
13421
|
+
sage: U == B * B.H
|
|
13422
|
+
True
|
|
13423
|
+
sage: U = matrix(GF(7**2), [[0, 1, 2], [1, 0, 1], [2, 1, 0]])
|
|
13424
|
+
sage: B = U._cholesky_extended_ff(); B
|
|
13425
|
+
[4*z2 + 2 6*z2 0]
|
|
13426
|
+
[4*z2 + 2 z2 0]
|
|
13427
|
+
[5*z2 + 6 z2 z2]
|
|
13428
|
+
sage: U == B * B.H
|
|
13429
|
+
True
|
|
13430
|
+
|
|
13431
|
+
TESTS:
|
|
13432
|
+
|
|
13433
|
+
If the matrix is not full rank, we compute the rank and throw an exception.
|
|
13434
|
+
|
|
13435
|
+
sage: # needs sage.rings.finite_rings
|
|
13436
|
+
sage: U = matrix(GF(3**2),[[1,4,7],[4,1,4],[7,4,1]])
|
|
13437
|
+
sage: U._cholesky_extended_ff()
|
|
13438
|
+
Traceback (most recent call last):
|
|
13439
|
+
...
|
|
13440
|
+
ValueError: matrix is not full rank
|
|
13441
|
+
sage: U = matrix(GF(3**2),[[0,4,7],[4,1,4],[7,4,1]])
|
|
13442
|
+
sage: U._cholesky_extended_ff()
|
|
13443
|
+
Traceback (most recent call last):
|
|
13444
|
+
...
|
|
13445
|
+
ValueError: matrix is not full rank
|
|
13446
|
+
"""
|
|
13447
|
+
from sage.matrix.constructor import identity_matrix
|
|
13448
|
+
|
|
13449
|
+
if not self.is_hermitian():
|
|
13450
|
+
raise ValueError("matrix is not Hermitian")
|
|
13451
|
+
|
|
13452
|
+
F = self._base_ring
|
|
13453
|
+
n = self.nrows()
|
|
13454
|
+
if self.fetch("rank") not in [n, None]:
|
|
13455
|
+
raise ValueError("matrix is not full rank")
|
|
13456
|
+
if not (F.is_finite() and F.order().is_square()):
|
|
13457
|
+
raise ValueError("the base ring must be a finite field of square order")
|
|
13458
|
+
|
|
13459
|
+
q = F.order().sqrt(extend=False)
|
|
13460
|
+
|
|
13461
|
+
def conj_square_root(u):
|
|
13462
|
+
if u == 0:
|
|
13463
|
+
return 0
|
|
13464
|
+
z = F.multiplicative_generator()
|
|
13465
|
+
k = u.log(z)
|
|
13466
|
+
if k % (q + 1) != 0:
|
|
13467
|
+
raise ValueError(f"unable to factor: {u} is not in base field GF({q})")
|
|
13468
|
+
return z ** (k//(q+1))
|
|
13469
|
+
|
|
13470
|
+
if self.nrows() == 1 and self.ncols() == 1:
|
|
13471
|
+
return self.__class__(F, [conj_square_root(self[0][0])])
|
|
13472
|
+
|
|
13473
|
+
A = copy(self)
|
|
13474
|
+
D = identity_matrix(F, n)
|
|
13475
|
+
row = -1
|
|
13476
|
+
|
|
13477
|
+
# Diagonalize A
|
|
13478
|
+
while row != n - 1:
|
|
13479
|
+
row += 1
|
|
13480
|
+
|
|
13481
|
+
# Look for a non-zero element on the main diagonal, starting from `row`
|
|
13482
|
+
i = row
|
|
13483
|
+
while i < n and A[i, i].is_zero():
|
|
13484
|
+
i += 1
|
|
13485
|
+
|
|
13486
|
+
if i == row:
|
|
13487
|
+
# Do nothing since A[row, row] != 0
|
|
13488
|
+
pass
|
|
13489
|
+
elif i < n:
|
|
13490
|
+
# Swap to ensure A[row, row] != 0
|
|
13491
|
+
A.swap_rows(row, i)
|
|
13492
|
+
A.swap_columns(row, i)
|
|
13493
|
+
D.swap_rows(row, i)
|
|
13494
|
+
else:
|
|
13495
|
+
# All entries on the main diagonal are zero; look for an off-diagonal element
|
|
13496
|
+
i = row
|
|
13497
|
+
while i < n - 1:
|
|
13498
|
+
k = i + 1
|
|
13499
|
+
while k < n and A[i, k].is_zero():
|
|
13500
|
+
k += 1
|
|
13501
|
+
if k == n:
|
|
13502
|
+
i += 1
|
|
13503
|
+
else:
|
|
13504
|
+
break
|
|
13505
|
+
|
|
13506
|
+
if i == n - 1:
|
|
13507
|
+
# All elements are zero; terminate
|
|
13508
|
+
row -= 1
|
|
13509
|
+
r = row + 1
|
|
13510
|
+
break
|
|
13511
|
+
|
|
13512
|
+
# Fetch the non-zero element and place it at A[row, row + 1]
|
|
13513
|
+
if i != row:
|
|
13514
|
+
A.swap_rows(row, i)
|
|
13515
|
+
A.swap_columns(row, i)
|
|
13516
|
+
D.swap_rows(row, i)
|
|
13517
|
+
|
|
13518
|
+
A.swap_rows(row + 1, k)
|
|
13519
|
+
A.swap_columns(row + 1, k)
|
|
13520
|
+
D.swap_rows(row + 1, k)
|
|
13521
|
+
|
|
13522
|
+
b = ~A[row + 1, row]
|
|
13523
|
+
A.add_multiple_of_column(row, row + 1, b**q)
|
|
13524
|
+
A.add_multiple_of_row(row, row + 1, b)
|
|
13525
|
+
D.add_multiple_of_row(row, row + 1, b)
|
|
13526
|
+
|
|
13527
|
+
# Eliminate below-diagonal entries in the current column
|
|
13528
|
+
a = ~(-A[row, row])
|
|
13529
|
+
for i in range(row + 1, n):
|
|
13530
|
+
b = A[i, row] * a
|
|
13531
|
+
if not b.is_zero():
|
|
13532
|
+
A.add_multiple_of_column(i, row, b**q)
|
|
13533
|
+
A.add_multiple_of_row(i, row, b)
|
|
13534
|
+
D.add_multiple_of_row(i, row, b)
|
|
13535
|
+
|
|
13536
|
+
# Count how many variables have been used
|
|
13537
|
+
if row == n - 1:
|
|
13538
|
+
if A[n - 1, n - 1]: # nonzero entry
|
|
13539
|
+
r = n
|
|
13540
|
+
else:
|
|
13541
|
+
r = n - 1
|
|
13542
|
+
|
|
13543
|
+
if r < n:
|
|
13544
|
+
self.cache('rank', r)
|
|
13545
|
+
raise ValueError("matrix is not full rank")
|
|
13546
|
+
|
|
13547
|
+
# Normalize diagonal elements to 1
|
|
13548
|
+
for i in range(r):
|
|
13549
|
+
a = A[i, i]
|
|
13550
|
+
if not a.is_one():
|
|
13551
|
+
# Find an element `b` such that `a = b*b^q = b^(q+1)`
|
|
13552
|
+
b = conj_square_root(a)
|
|
13553
|
+
D.rescale_row(i, 1 / b)
|
|
13554
|
+
|
|
13555
|
+
return D.inverse()
|
|
13556
|
+
|
|
13557
|
+
def cholesky(self, extended=False):
|
|
12959
13558
|
r"""
|
|
12960
13559
|
Return the Cholesky decomposition of a Hermitian matrix.
|
|
12961
13560
|
|
|
@@ -13001,6 +13600,15 @@ cdef class Matrix(Matrix1):
|
|
|
13001
13600
|
closure or the algebraic reals, depending on whether or not
|
|
13002
13601
|
imaginary numbers are required.
|
|
13003
13602
|
|
|
13603
|
+
Over finite fields, the Cholesky decomposition might
|
|
13604
|
+
not exist, but when the field has square order (i.e.,
|
|
13605
|
+
`\GF{q^2}`), then we can perform the conjugate-symmetric
|
|
13606
|
+
version of Gaussian elimination, but the resulting
|
|
13607
|
+
decomposition matrix `L` might not be lower triangular.
|
|
13608
|
+
|
|
13609
|
+
This is a translation of ``BaseChangeToCanonical`` from
|
|
13610
|
+
the GAP ``forms`` package (for a Hermitian form).
|
|
13611
|
+
|
|
13004
13612
|
EXAMPLES:
|
|
13005
13613
|
|
|
13006
13614
|
This simple example has a result with entries that remain
|
|
@@ -13171,6 +13779,31 @@ cdef class Matrix(Matrix1):
|
|
|
13171
13779
|
...
|
|
13172
13780
|
ValueError: matrix is not positive definite
|
|
13173
13781
|
|
|
13782
|
+
Here we use the extended decomposition, where the result
|
|
13783
|
+
may not be a lower triangular matrix::
|
|
13784
|
+
|
|
13785
|
+
sage: # needs sage.rings.finite_rings
|
|
13786
|
+
sage: U = matrix(GF(5**2),[[0,1],[1,0]])
|
|
13787
|
+
sage: B = U.cholesky(extended=True); B
|
|
13788
|
+
[3*z2 4*z2]
|
|
13789
|
+
[3*z2 z2]
|
|
13790
|
+
sage: U == B * B.H
|
|
13791
|
+
True
|
|
13792
|
+
sage: U = matrix(GF(11**2),[[1,4,7],[4,1,4],[7,4,1]])
|
|
13793
|
+
sage: B = U.cholesky(extended=True); B
|
|
13794
|
+
[ 1 0 0]
|
|
13795
|
+
[ 4 9*z2 + 2 0]
|
|
13796
|
+
[ 7 10*z2 + 1 3*z2 + 3]
|
|
13797
|
+
sage: U == B * B.H
|
|
13798
|
+
True
|
|
13799
|
+
sage: U = matrix(GF(3**2), [[0, 1, 2], [1, 0, 1], [2, 1, 0]])
|
|
13800
|
+
sage: B = U.cholesky(extended=True); B
|
|
13801
|
+
[2*z2 2 0]
|
|
13802
|
+
[2*z2 1 0]
|
|
13803
|
+
[ 0 1 z2]
|
|
13804
|
+
sage: U == B * B.H
|
|
13805
|
+
True
|
|
13806
|
+
|
|
13174
13807
|
TESTS:
|
|
13175
13808
|
|
|
13176
13809
|
This verifies that :issue:`11274` is resolved::
|
|
@@ -13217,7 +13850,22 @@ cdef class Matrix(Matrix1):
|
|
|
13217
13850
|
sage: all( matrix(R,[]).cholesky().is_immutable() # needs sage.rings.number_field
|
|
13218
13851
|
....: for R in (RR,CC,RDF,CDF,ZZ,QQ,AA,QQbar) )
|
|
13219
13852
|
True
|
|
13853
|
+
|
|
13854
|
+
Perform the extended decomposition over finite fields, which may result in non upper/lower triangular matrices::
|
|
13855
|
+
|
|
13856
|
+
sage: # needs sage.rings.finite_rings
|
|
13857
|
+
sage: A = matrix(GF(11**2),[[1,4,7],[4,1,4],[7,4,1]])
|
|
13858
|
+
sage: B = A.cholesky(extended=True)
|
|
13859
|
+
sage: A == B * B.H
|
|
13860
|
+
True
|
|
13861
|
+
sage: A = matrix(GF(3**2), [[0, 1, 2], [1, 0, 1], [2, 1, 0]])
|
|
13862
|
+
sage: B = A.cholesky(extended=True)
|
|
13863
|
+
sage: A == B * B.H
|
|
13864
|
+
True
|
|
13220
13865
|
"""
|
|
13866
|
+
if extended:
|
|
13867
|
+
return self._cholesky_extended_ff()
|
|
13868
|
+
|
|
13221
13869
|
cdef Matrix C # output matrix
|
|
13222
13870
|
C = self.fetch('cholesky')
|
|
13223
13871
|
if C is not None:
|
|
@@ -15476,6 +16124,10 @@ cdef class Matrix(Matrix1):
|
|
|
15476
16124
|
Return the conjugate of self, i.e. the matrix whose entries are the
|
|
15477
16125
|
conjugates of the entries of ``self``.
|
|
15478
16126
|
|
|
16127
|
+
.. SEEALSO::
|
|
16128
|
+
|
|
16129
|
+
:attr:`C`
|
|
16130
|
+
|
|
15479
16131
|
EXAMPLES::
|
|
15480
16132
|
|
|
15481
16133
|
sage: # needs sage.rings.complex_double sage.symbolic
|
|
@@ -15531,6 +16183,10 @@ cdef class Matrix(Matrix1):
|
|
|
15531
16183
|
though there is substantial variation and some confusion with
|
|
15532
16184
|
the use of that term.
|
|
15533
16185
|
|
|
16186
|
+
.. SEEALSO::
|
|
16187
|
+
|
|
16188
|
+
:meth:`conjugate`, :meth:`~.Matrix_dense.transpose`, :attr:`H`
|
|
16189
|
+
|
|
15534
16190
|
OUTPUT:
|
|
15535
16191
|
|
|
15536
16192
|
A matrix formed by taking the complex conjugate of every entry
|
|
@@ -15958,7 +16614,11 @@ cdef class Matrix(Matrix1):
|
|
|
15958
16614
|
"""
|
|
15959
16615
|
d = self.smith_form(transformation=False)
|
|
15960
16616
|
r = min(self.nrows(), self.ncols())
|
|
15961
|
-
|
|
16617
|
+
ed = [d[i, i] for i in range(r)]
|
|
16618
|
+
try:
|
|
16619
|
+
return [x.canonical_associate()[0] for x in ed]
|
|
16620
|
+
except (AttributeError, TypeError):
|
|
16621
|
+
return ed
|
|
15962
16622
|
|
|
15963
16623
|
def smith_form(self, transformation=True, integral=None, exact=True):
|
|
15964
16624
|
r"""
|
|
@@ -16138,7 +16798,7 @@ cdef class Matrix(Matrix1):
|
|
|
16138
16798
|
sage: d, u, v = m.smith_form(); u * m * v == d
|
|
16139
16799
|
True
|
|
16140
16800
|
|
|
16141
|
-
Over local fields, we can request the transformation matrices to be integral
|
|
16801
|
+
Over local fields, we can request the transformation matrices to be integral::
|
|
16142
16802
|
|
|
16143
16803
|
sage: K = Qp(2, 5, print_mode='terse') # needs sage.rings.padics
|
|
16144
16804
|
sage: M = matrix(K, 2, 3, [1/2, 1, 2, 1/3, 1, 3]) # needs sage.rings.padics
|
|
@@ -16589,7 +17249,7 @@ cdef class Matrix(Matrix1):
|
|
|
16589
17249
|
....: -2*a^2 + 4*a - 2, -2*a^2 + 1, 2*a, a^2 - 6, 3*a^2 - a ])
|
|
16590
17250
|
sage: r,s,p = m._echelon_form_PID()
|
|
16591
17251
|
sage: s[2]
|
|
16592
|
-
(0, 0,
|
|
17252
|
+
(0, 0, 3*a^2 + 18*a - 34, 68*a^2 - 134*a + 53, 111*a^2 - 275*a + 90)
|
|
16593
17253
|
sage: r * m == s and r.det() == 1
|
|
16594
17254
|
True
|
|
16595
17255
|
|
|
@@ -18189,6 +18849,540 @@ cdef class Matrix(Matrix1):
|
|
|
18189
18849
|
return all(s * (self * x) == 0
|
|
18190
18850
|
for (x, s) in K.discrete_complementarity_set())
|
|
18191
18851
|
|
|
18852
|
+
def _matrix_cmr(self):
|
|
18853
|
+
r"""
|
|
18854
|
+
Return ``self`` as a :class:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse`.
|
|
18855
|
+
|
|
18856
|
+
EXAMPLES::
|
|
18857
|
+
|
|
18858
|
+
sage: # needs sage.libs.cmr
|
|
18859
|
+
sage: M = matrix(ZZ, [[1, 0, 1], [0, 1, 1], [1, 2, 3]],
|
|
18860
|
+
....: column_keys=['a', 'b', 'c'],
|
|
18861
|
+
....: row_keys=['u', 'v', 'w'])
|
|
18862
|
+
sage: M_cmr = M._matrix_cmr(); M_cmr
|
|
18863
|
+
[1 0 1]
|
|
18864
|
+
[0 1 1]
|
|
18865
|
+
[1 2 3]
|
|
18866
|
+
sage: type(M_cmr)
|
|
18867
|
+
<class 'sage.matrix.matrix_cmr_sparse.Matrix_cmr_chr_sparse'>
|
|
18868
|
+
"""
|
|
18869
|
+
from .matrix_cmr_sparse import Matrix_cmr_chr_sparse
|
|
18870
|
+
from .matrix_space import MatrixSpace
|
|
18871
|
+
|
|
18872
|
+
MS = MatrixSpace(ZZ, self.nrows(), self.ncols(), sparse=True)
|
|
18873
|
+
return Matrix_cmr_chr_sparse(MS, self)
|
|
18874
|
+
|
|
18875
|
+
def is_unimodular(self, *args, **kwds):
|
|
18876
|
+
r"""
|
|
18877
|
+
Return whether ``self`` is a unimodular matrix.
|
|
18878
|
+
|
|
18879
|
+
A nonsingular square matrix `A` is called unimodular if it is integral
|
|
18880
|
+
and has determinant `\pm1`, i.e., an element of
|
|
18881
|
+
`\mathop{\operatorname{GL}}_n(\ZZ)` [Sch1986]_, Ch. 4.3.
|
|
18882
|
+
|
|
18883
|
+
A rectangular matrix `A` of full row rank is called unimodular if it
|
|
18884
|
+
is integral and every basis `B` of `A` has determinant `\pm1`.
|
|
18885
|
+
[Sch1986]_, Ch. 19.1.
|
|
18886
|
+
|
|
18887
|
+
More generally, a matrix `A` of rank `r` is called unimodular if it is
|
|
18888
|
+
integral and for every submatrix `B` formed by `r` linearly independent columns,
|
|
18889
|
+
the greatest common divisor of the determinants of all `r`-by-`r`
|
|
18890
|
+
submatrices of `B` is `1`. [Sch1986]_, Ch. 21.4.
|
|
18891
|
+
|
|
18892
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_unimodular` for
|
|
18893
|
+
the detailed documentation.
|
|
18894
|
+
|
|
18895
|
+
.. SEEALSO:: :meth:`is_k_equimodular`, :meth:`is_strongly_unimodular`, :meth:`is_totally_unimodular`
|
|
18896
|
+
|
|
18897
|
+
EXAMPLES::
|
|
18898
|
+
|
|
18899
|
+
sage: # needs sage.libs.cmr
|
|
18900
|
+
sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]]); M
|
|
18901
|
+
[1 0 0]
|
|
18902
|
+
[0 1 0]
|
|
18903
|
+
sage: M.is_unimodular()
|
|
18904
|
+
True
|
|
18905
|
+
sage: M = matrix(ZZ, [[1, 1, 0], [-1, 1, 1]]); M
|
|
18906
|
+
[ 1 1 0]
|
|
18907
|
+
[-1 1 1]
|
|
18908
|
+
sage: M.is_unimodular()
|
|
18909
|
+
False
|
|
18910
|
+
"""
|
|
18911
|
+
return self._matrix_cmr().is_unimodular(*args, **kwds)
|
|
18912
|
+
|
|
18913
|
+
def is_strongly_unimodular(self, *args, **kwds):
|
|
18914
|
+
r"""
|
|
18915
|
+
Return whether ``self`` is a strongly unimodular matrix.
|
|
18916
|
+
|
|
18917
|
+
A matrix is strongly unimodular if ``self`` and ``self.transpose()`` are both unimodular.
|
|
18918
|
+
|
|
18919
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_strongly_unimodular` for
|
|
18920
|
+
the detailed documentation.
|
|
18921
|
+
|
|
18922
|
+
.. SEEALSO:: :meth:`is_unimodular`, :meth:`is_strongly_k_equimodular`
|
|
18923
|
+
|
|
18924
|
+
EXAMPLES::
|
|
18925
|
+
|
|
18926
|
+
sage: # needs sage.libs.cmr
|
|
18927
|
+
sage: M = matrix([[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M
|
|
18928
|
+
[1 0 1]
|
|
18929
|
+
[0 1 1]
|
|
18930
|
+
[1 2 3]
|
|
18931
|
+
sage: M.is_unimodular()
|
|
18932
|
+
True
|
|
18933
|
+
sage: M.is_strongly_unimodular()
|
|
18934
|
+
False
|
|
18935
|
+
sage: M = matrix([[1, 0, 0], [0, 1, 0]]); M
|
|
18936
|
+
[1 0 0]
|
|
18937
|
+
[0 1 0]
|
|
18938
|
+
sage: M.is_strongly_unimodular()
|
|
18939
|
+
True
|
|
18940
|
+
"""
|
|
18941
|
+
return self._matrix_cmr().is_strongly_unimodular(*args, **kwds)
|
|
18942
|
+
|
|
18943
|
+
def equimodulus(self, *args, **kwds):
|
|
18944
|
+
r"""
|
|
18945
|
+
Return the integer `k` such that ``self`` is
|
|
18946
|
+
equimodular with determinant gcd `k`.
|
|
18947
|
+
|
|
18948
|
+
A matrix `M` of rank `r` is equimodular with determinant gcd `k`
|
|
18949
|
+
if the following two conditions are satisfied:
|
|
18950
|
+
|
|
18951
|
+
- for some column basis `B` of `M`, the greatest common divisor of
|
|
18952
|
+
the determinants of all `r`-by-`r` submatrices of `B` is `k`;
|
|
18953
|
+
|
|
18954
|
+
- the matrix `X` such that `M=BX` is totally unimodular.
|
|
18955
|
+
|
|
18956
|
+
OUTPUT:
|
|
18957
|
+
|
|
18958
|
+
- ``k``: ``self`` is equimodular with determinant gcd `k`
|
|
18959
|
+
- ``None``: ``self`` is not equimodular for any `k`
|
|
18960
|
+
|
|
18961
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.equimodulus` for
|
|
18962
|
+
the detailed documentation.
|
|
18963
|
+
|
|
18964
|
+
.. SEEALSO:: :meth:`is_k_equimodular`, :meth:`strong_equimodulus`
|
|
18965
|
+
|
|
18966
|
+
EXAMPLES::
|
|
18967
|
+
|
|
18968
|
+
sage: # needs sage.libs.cmr
|
|
18969
|
+
sage: M = matrix([[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M
|
|
18970
|
+
[1 0 1]
|
|
18971
|
+
[0 1 1]
|
|
18972
|
+
[1 2 3]
|
|
18973
|
+
sage: M.equimodulus()
|
|
18974
|
+
1
|
|
18975
|
+
sage: M = matrix([[1, 1, 1], [0, 1, 3]]); M
|
|
18976
|
+
[1 1 1]
|
|
18977
|
+
[0 1 3]
|
|
18978
|
+
sage: M.equimodulus()
|
|
18979
|
+
"""
|
|
18980
|
+
return self._matrix_cmr().equimodulus(*args, **kwds)
|
|
18981
|
+
|
|
18982
|
+
def strong_equimodulus(self, *args, **kwds):
|
|
18983
|
+
r"""
|
|
18984
|
+
Return the integer `k` such that ``self`` is
|
|
18985
|
+
strongly equimodular with determinant gcd `k`.
|
|
18986
|
+
|
|
18987
|
+
Return whether ``self`` is strongly `k`-equimodular.
|
|
18988
|
+
|
|
18989
|
+
A matrix is strongly equimodular if ``self`` and ``self.transpose()``
|
|
18990
|
+
are both equimodular, which implies that they are equimodular for
|
|
18991
|
+
the same determinant gcd `k`.
|
|
18992
|
+
A matrix `M` of rank-`r` is `k`-equimodular if the following two conditions
|
|
18993
|
+
are satisfied:
|
|
18994
|
+
|
|
18995
|
+
- for some column basis `B` of `M`, the greatest common divisor of the
|
|
18996
|
+
determinants of all `r`-by-`r` submatrices of `B` is `k`;
|
|
18997
|
+
|
|
18998
|
+
- the matrix `X` such that `M=BX` is totally unimodular.
|
|
18999
|
+
|
|
19000
|
+
OUTPUT:
|
|
19001
|
+
|
|
19002
|
+
- ``k``: ``self`` is `k`-equimodular
|
|
19003
|
+
- ``None``: ``self`` is not `k`-equimodular for any `k`
|
|
19004
|
+
|
|
19005
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.strong_equimodulus` for
|
|
19006
|
+
the detailed documentation.
|
|
19007
|
+
|
|
19008
|
+
.. SEEALSO:: :meth:`is_strongly_k_equimodular`, :meth:`equimodulus`
|
|
19009
|
+
|
|
19010
|
+
EXAMPLES::
|
|
19011
|
+
|
|
19012
|
+
sage: # needs sage.libs.cmr
|
|
19013
|
+
sage: M = matrix([[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M
|
|
19014
|
+
[1 0 1]
|
|
19015
|
+
[0 1 1]
|
|
19016
|
+
[1 2 3]
|
|
19017
|
+
sage: M.strong_equimodulus()
|
|
19018
|
+
sage: M = matrix([[1, 0, 0], [0, 1, 0]]); M
|
|
19019
|
+
[1 0 0]
|
|
19020
|
+
[0 1 0]
|
|
19021
|
+
sage: M.strong_equimodulus()
|
|
19022
|
+
1
|
|
19023
|
+
"""
|
|
19024
|
+
return self._matrix_cmr().strong_equimodulus(*args, **kwds)
|
|
19025
|
+
|
|
19026
|
+
def is_k_equimodular(self, k, *args, **kwds):
|
|
19027
|
+
r"""
|
|
19028
|
+
Return whether ``self`` is equimodular with determinant gcd `k`.
|
|
19029
|
+
|
|
19030
|
+
A matrix `M` of rank-`r` is `k`-equimodular if the following two
|
|
19031
|
+
conditions are satisfied:
|
|
19032
|
+
|
|
19033
|
+
- for some column basis `B` of `M`, the greatest common divisor of
|
|
19034
|
+
the determinants of all `r`-by-`r` submatrices of `B` is `k`;
|
|
19035
|
+
|
|
19036
|
+
- the matrix `X` such that `M=BX` is totally unimodular.
|
|
19037
|
+
|
|
19038
|
+
If the matrix has full row rank, it is `k`-equimodular if
|
|
19039
|
+
every full rank minor of the matrix has determinant `0,\pm k`.
|
|
19040
|
+
|
|
19041
|
+
.. NOTE::
|
|
19042
|
+
|
|
19043
|
+
In parts of the literature, a matrix with the above properties
|
|
19044
|
+
is called *strictly* `k`-modular.
|
|
19045
|
+
|
|
19046
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_k_equimodular` for
|
|
19047
|
+
the detailed documentation.
|
|
19048
|
+
|
|
19049
|
+
.. SEEALSO:: :meth:`is_unimodular`, :meth:`is_strongly_k_equimodular`,
|
|
19050
|
+
:meth:`equimodulus`
|
|
19051
|
+
|
|
19052
|
+
EXAMPLES::
|
|
19053
|
+
|
|
19054
|
+
sage: # needs sage.libs.cmr
|
|
19055
|
+
sage: M = matrix([[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M
|
|
19056
|
+
[1 0 1]
|
|
19057
|
+
[0 1 1]
|
|
19058
|
+
[1 2 3]
|
|
19059
|
+
sage: M.is_k_equimodular(1)
|
|
19060
|
+
True
|
|
19061
|
+
sage: M.is_k_equimodular(2)
|
|
19062
|
+
False
|
|
19063
|
+
sage: M = matrix([[1, 1, 1], [0, 1, 3]]); M
|
|
19064
|
+
[1 1 1]
|
|
19065
|
+
[0 1 3]
|
|
19066
|
+
sage: M.is_k_equimodular(1)
|
|
19067
|
+
False
|
|
19068
|
+
"""
|
|
19069
|
+
return self._matrix_cmr().is_k_equimodular(k, *args, **kwds)
|
|
19070
|
+
|
|
19071
|
+
def is_strongly_k_equimodular(self, k, *args, **kwds):
|
|
19072
|
+
r"""
|
|
19073
|
+
Return whether ``self`` is strongly `k`-equimodular.
|
|
19074
|
+
|
|
19075
|
+
A matrix is strongly `k`-equimodular if ``self`` and ``self.transpose()``
|
|
19076
|
+
are both `k`-equimodular.
|
|
19077
|
+
|
|
19078
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_strongly_k_equimodular` for
|
|
19079
|
+
the detailed documentation.
|
|
19080
|
+
|
|
19081
|
+
.. SEEALSO:: :meth:`is_k_equimodular`, :meth:`is_strongly_unimodular`,
|
|
19082
|
+
:meth:`strong_equimodulus`
|
|
19083
|
+
|
|
19084
|
+
EXAMPLES::
|
|
19085
|
+
|
|
19086
|
+
sage: # needs sage.libs.cmr
|
|
19087
|
+
sage: M = matrix([[1, 0, 1], [0, 1, 1], [1, 2, 3]]); M
|
|
19088
|
+
[1 0 1]
|
|
19089
|
+
[0 1 1]
|
|
19090
|
+
[1 2 3]
|
|
19091
|
+
sage: M.is_strongly_k_equimodular(1)
|
|
19092
|
+
False
|
|
19093
|
+
sage: M = matrix([[1, 0, 0], [0, 1, 0]]); M
|
|
19094
|
+
[1 0 0]
|
|
19095
|
+
[0 1 0]
|
|
19096
|
+
sage: M.is_strongly_k_equimodular(1)
|
|
19097
|
+
True
|
|
19098
|
+
"""
|
|
19099
|
+
return self._matrix_cmr().is_strongly_k_equimodular(k, *args, **kwds)
|
|
19100
|
+
|
|
19101
|
+
def is_network_matrix(self, *args, **kwds):
|
|
19102
|
+
r"""
|
|
19103
|
+
Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a network matrix.
|
|
19104
|
+
|
|
19105
|
+
If there is some entry not in `\{-1, 0, 1\}`, return ``False``.
|
|
19106
|
+
|
|
19107
|
+
Let `D = (V,A)` be a digraph and let `T` be an (arbitrarily) directed
|
|
19108
|
+
spanning forest of the underlying undirected graph.
|
|
19109
|
+
The matrix `M(D,T) \in \{-1,0,1\}^{T \times (A \setminus T)}` defined via
|
|
19110
|
+
|
|
19111
|
+
.. MATH::
|
|
19112
|
+
|
|
19113
|
+
M(D,T)_{a,(v,w)} := \begin{cases}
|
|
19114
|
+
+1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ forwardly}, \\
|
|
19115
|
+
-1 & \text{if the unique $v$-$w$-path in $T$ passes through $a$ backwardly}, \\
|
|
19116
|
+
0 & \text{otherwise}
|
|
19117
|
+
\end{cases}
|
|
19118
|
+
|
|
19119
|
+
is called the network matrix of `D` with respect to `T`.
|
|
19120
|
+
A matrix `M` is called network matrix if there exists a digraph `D`
|
|
19121
|
+
with a directed spanning forest `T` such that `M = M(D,T)`.
|
|
19122
|
+
Moreover, `M` is called conetwork matrix if `M^T` is a network matrix.
|
|
19123
|
+
|
|
19124
|
+
ALGORITHM:
|
|
19125
|
+
|
|
19126
|
+
The implemented recognition algorithm first tests the binary matroid of
|
|
19127
|
+
the support matrix of `M` for being graphic and
|
|
19128
|
+
uses camion for testing whether `M` is signed correctly.
|
|
19129
|
+
|
|
19130
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_network_matrix` for
|
|
19131
|
+
the detailed documentation.
|
|
19132
|
+
|
|
19133
|
+
EXAMPLES::
|
|
19134
|
+
|
|
19135
|
+
sage: # needs sage.libs.cmr
|
|
19136
|
+
sage: M = matrix([[1, 0], [2, 1], [0, -1]]); M
|
|
19137
|
+
[ 1 0]
|
|
19138
|
+
[ 2 1]
|
|
19139
|
+
[ 0 -1]
|
|
19140
|
+
sage: M.is_network_matrix()
|
|
19141
|
+
False
|
|
19142
|
+
sage: M = matrix([[1, 0], [-1, 1], [0, -1]]); M
|
|
19143
|
+
[ 1 0]
|
|
19144
|
+
[-1 1]
|
|
19145
|
+
[ 0 -1]
|
|
19146
|
+
sage: M.is_network_matrix()
|
|
19147
|
+
True
|
|
19148
|
+
sage: result, certificate = M.is_network_matrix(certificate=True)
|
|
19149
|
+
sage: graph, forest_edges, coforest_edges = certificate
|
|
19150
|
+
sage: graph
|
|
19151
|
+
Digraph on 4 vertices
|
|
19152
|
+
sage: graph.vertices(sort=True) # the numbers have no meaning
|
|
19153
|
+
[1, 2, 7, 12]
|
|
19154
|
+
sage: graph.edges(sort=True, labels=False)
|
|
19155
|
+
[(2, 1), (2, 7), (7, 1), (7, 12), (12, 1)]
|
|
19156
|
+
sage: forest_edges # indexed by rows of M
|
|
19157
|
+
((2, 1), (7, 1), (7, 12))
|
|
19158
|
+
sage: coforest_edges # indexed by cols of M
|
|
19159
|
+
((2, 7), (12, 1))
|
|
19160
|
+
sage: K33 = matrix([[-1, -1, -1, -1],
|
|
19161
|
+
....: [ 1, 1, 0, 0],
|
|
19162
|
+
....: [ 0, 0, 1, 1],
|
|
19163
|
+
....: [ 1, 0, 1, 0],
|
|
19164
|
+
....: [ 0, 1, 0, 1]]); K33
|
|
19165
|
+
[-1 -1 -1 -1]
|
|
19166
|
+
[ 1 1 0 0]
|
|
19167
|
+
[ 0 0 1 1]
|
|
19168
|
+
[ 1 0 1 0]
|
|
19169
|
+
[ 0 1 0 1]
|
|
19170
|
+
sage: K33.is_network_matrix()
|
|
19171
|
+
True
|
|
19172
|
+
|
|
19173
|
+
This is test ``Basic`` in CMR's ``test_network.cpp``::
|
|
19174
|
+
|
|
19175
|
+
sage: # needs sage.libs.cmr
|
|
19176
|
+
sage: M = matrix([[-1, 0, 0, 0, 1, -1, 0],
|
|
19177
|
+
....: [ 1, 0, 0, 1, -1, 1, 0],
|
|
19178
|
+
....: [ 0, -1, 0, -1, 1, -1, 0],
|
|
19179
|
+
....: [ 0, 1, 0, 0, 0, 0, 1],
|
|
19180
|
+
....: [ 0, 0, 1, -1, 1, 0, 1],
|
|
19181
|
+
....: [ 0, 0, -1, 1, -1, 0, 0]])
|
|
19182
|
+
sage: M.is_network_matrix()
|
|
19183
|
+
True
|
|
19184
|
+
sage: result, certificate = M.is_network_matrix(certificate=True)
|
|
19185
|
+
sage: result, certificate
|
|
19186
|
+
(True,
|
|
19187
|
+
(Digraph on 7 vertices,
|
|
19188
|
+
((9, 8), (3, 8), (3, 4), (5, 4), (4, 6), (0, 6)),
|
|
19189
|
+
((3, 9), (5, 3), (4, 0), (0, 8), (9, 0), (4, 9), (5, 6))))
|
|
19190
|
+
sage: digraph, forest_arcs, coforest_arcs = certificate
|
|
19191
|
+
sage: list(digraph.edges(sort=True))
|
|
19192
|
+
[(0, 6, None), (0, 8, None),
|
|
19193
|
+
(3, 4, None), (3, 8, None), (3, 9, None),
|
|
19194
|
+
(4, 0, None), (4, 6, None), (4, 9, None),
|
|
19195
|
+
(5, 3, None), (5, 4, None), (5, 6, None),
|
|
19196
|
+
(9, 0, None), (9, 8, None)]
|
|
19197
|
+
sage: digraph.plot(edge_colors={'red': forest_arcs}) # needs sage.plot
|
|
19198
|
+
Graphics object consisting of 21 graphics primitives
|
|
19199
|
+
"""
|
|
19200
|
+
return self._matrix_cmr().is_network_matrix(*args, **kwds)
|
|
19201
|
+
|
|
19202
|
+
def is_conetwork_matrix(self, *args, **kwds):
|
|
19203
|
+
r"""
|
|
19204
|
+
Return whether the matrix ``self`` over `\GF{3}` or `\QQ` is a conetwork matrix.
|
|
19205
|
+
|
|
19206
|
+
A matrix is a conetwork matrix if and only if its transpose is a network matrix.
|
|
19207
|
+
|
|
19208
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_conetwork_matrix` for
|
|
19209
|
+
the detailed documentation.
|
|
19210
|
+
|
|
19211
|
+
.. SEEALSO:: :meth:`is_network_matrix`
|
|
19212
|
+
|
|
19213
|
+
EXAMPLES::
|
|
19214
|
+
|
|
19215
|
+
sage: # needs sage.libs.cmr
|
|
19216
|
+
sage: M = matrix([[1, 0, 0, 0, 1, -1, 1, 0, 0],
|
|
19217
|
+
....: [0, 1, 0, 0, 0, 1, -1, 1, 0],
|
|
19218
|
+
....: [0, 0, 1, 0, 0, 0, 1, -1, 1],
|
|
19219
|
+
....: [0, 0, 0, 1, 1, 0, 0, 1, -1]]); M
|
|
19220
|
+
[ 1 0 0 0 1 -1 1 0 0]
|
|
19221
|
+
[ 0 1 0 0 0 1 -1 1 0]
|
|
19222
|
+
[ 0 0 1 0 0 0 1 -1 1]
|
|
19223
|
+
[ 0 0 0 1 1 0 0 1 -1]
|
|
19224
|
+
sage: M.is_conetwork_matrix()
|
|
19225
|
+
True
|
|
19226
|
+
sage: K33 = matrix([[-1, -1, -1, -1],
|
|
19227
|
+
....: [ 1, 1, 0, 0],
|
|
19228
|
+
....: [ 0, 0, 1, 1],
|
|
19229
|
+
....: [ 1, 0, 1, 0],
|
|
19230
|
+
....: [ 0, 1, 0, 1]]); K33
|
|
19231
|
+
[-1 -1 -1 -1]
|
|
19232
|
+
[ 1 1 0 0]
|
|
19233
|
+
[ 0 0 1 1]
|
|
19234
|
+
[ 1 0 1 0]
|
|
19235
|
+
[ 0 1 0 1]
|
|
19236
|
+
sage: K33.is_conetwork_matrix()
|
|
19237
|
+
False
|
|
19238
|
+
sage: C3 = matrix([[1, 1, 0],
|
|
19239
|
+
....: [1, 0, 1],
|
|
19240
|
+
....: [0, 1, 1]]); C3
|
|
19241
|
+
[1 1 0]
|
|
19242
|
+
[1 0 1]
|
|
19243
|
+
[0 1 1]
|
|
19244
|
+
sage: result, certificate = C3.is_conetwork_matrix(certificate=True)
|
|
19245
|
+
sage: result
|
|
19246
|
+
False
|
|
19247
|
+
"""
|
|
19248
|
+
return self._matrix_cmr().is_conetwork_matrix(*args, **kwds)
|
|
19249
|
+
|
|
19250
|
+
def is_totally_unimodular(self, *args, **kwds):
|
|
19251
|
+
r"""
|
|
19252
|
+
Return whether ``self`` is a totally unimodular matrix.
|
|
19253
|
+
|
|
19254
|
+
A matrix is totally unimodular if every subdeterminant is `0`, `1`, or `-1`.
|
|
19255
|
+
|
|
19256
|
+
REFERENCES:
|
|
19257
|
+
|
|
19258
|
+
- [Sch1986]_, Chapter 19
|
|
19259
|
+
|
|
19260
|
+
INPUT:
|
|
19261
|
+
|
|
19262
|
+
- ``certificate`` -- boolean (default: ``False``);
|
|
19263
|
+
if ``True``, then return
|
|
19264
|
+
a :class:`DecompositionNode` if ``self`` is totally unimodular;
|
|
19265
|
+
a submatrix with determinant not in `\{0, \pm1\}` if not.
|
|
19266
|
+
|
|
19267
|
+
- ``stop_when_nonTU`` -- boolean (default: ``True``);
|
|
19268
|
+
whether to stop decomposing once not TU is determined.
|
|
19269
|
+
|
|
19270
|
+
- ``row_keys`` -- a finite or enumerated family of arbitrary objects
|
|
19271
|
+
that index the rows of the matrix
|
|
19272
|
+
|
|
19273
|
+
- ``column_keys`` -- a finite or enumerated family of arbitrary objects
|
|
19274
|
+
that index the columns of the matrix
|
|
19275
|
+
|
|
19276
|
+
See :meth:`sage.matrix.matrix_cmr_sparse.Matrix_cmr_sparse.is_totally_unimodular` for
|
|
19277
|
+
the detailed documentation.
|
|
19278
|
+
|
|
19279
|
+
EXAMPLES::
|
|
19280
|
+
|
|
19281
|
+
sage: # needs sage.libs.cmr
|
|
19282
|
+
sage: M = matrix([[1, 0], [2, 1], [0, 1]]); M
|
|
19283
|
+
[1 0]
|
|
19284
|
+
[2 1]
|
|
19285
|
+
[0 1]
|
|
19286
|
+
sage: M.is_totally_unimodular()
|
|
19287
|
+
False
|
|
19288
|
+
sage: M = matrix([[1, 0], [-1, 1], [0, 1]]); M
|
|
19289
|
+
[ 1 0]
|
|
19290
|
+
[-1 1]
|
|
19291
|
+
[ 0 1]
|
|
19292
|
+
sage: M.is_totally_unimodular()
|
|
19293
|
+
True
|
|
19294
|
+
sage: M.is_totally_unimodular(certificate=True)
|
|
19295
|
+
(True, GraphicNode (3×2))
|
|
19296
|
+
sage: MF = matroids.catalog.Fano(); MF
|
|
19297
|
+
Fano: Binary matroid of rank 3 on 7 elements, type (3, 0)
|
|
19298
|
+
sage: MFR = MF.representation().change_ring(ZZ); MFR
|
|
19299
|
+
[1 0 0 0 1 1 1]
|
|
19300
|
+
[0 1 0 1 0 1 1]
|
|
19301
|
+
[0 0 1 1 1 0 1]
|
|
19302
|
+
sage: MFR2 = block_diagonal_matrix(MFR, MFR, sparse=True); MFR2
|
|
19303
|
+
[1 0 0 0 1 1 1|0 0 0 0 0 0 0]
|
|
19304
|
+
[0 1 0 1 0 1 1|0 0 0 0 0 0 0]
|
|
19305
|
+
[0 0 1 1 1 0 1|0 0 0 0 0 0 0]
|
|
19306
|
+
[-------------+-------------]
|
|
19307
|
+
[0 0 0 0 0 0 0|1 0 0 0 1 1 1]
|
|
19308
|
+
[0 0 0 0 0 0 0|0 1 0 1 0 1 1]
|
|
19309
|
+
[0 0 0 0 0 0 0|0 0 1 1 1 0 1]
|
|
19310
|
+
sage: MFR2.is_totally_unimodular(certificate=True)
|
|
19311
|
+
(False, (OneSumNode (6×14) with 2 children, ((2, 1, 0), (5, 4, 3))))
|
|
19312
|
+
sage: result, certificate = MFR2.is_totally_unimodular(certificate=True,
|
|
19313
|
+
....: stop_when_nonTU=True)
|
|
19314
|
+
sage: result, certificate
|
|
19315
|
+
(False, (OneSumNode (6×14) with 2 children, ((2, 1, 0), (5, 4, 3))))
|
|
19316
|
+
sage: submatrix = MFR2.matrix_from_rows_and_columns(*certificate[1]); submatrix
|
|
19317
|
+
[0 1 1]
|
|
19318
|
+
[1 0 1]
|
|
19319
|
+
[1 1 0]
|
|
19320
|
+
sage: submatrix.determinant()
|
|
19321
|
+
2
|
|
19322
|
+
|
|
19323
|
+
If the matrix is totally unimodular, it always returns
|
|
19324
|
+
a full decomposition as a certificate::
|
|
19325
|
+
|
|
19326
|
+
sage: # needs sage.libs.cmr
|
|
19327
|
+
sage: M = matrix([[-1,-1,-1,-1, 0, 0, 0, 0, 0],
|
|
19328
|
+
....: [1, 1, 0, 0, 0, 0, 0, 0, 0],
|
|
19329
|
+
....: [0, 0, 1, 1, 0, 0, 0, 0, 0],
|
|
19330
|
+
....: [1, 0, 1, 0, 0, 0, 0, 0, 0],
|
|
19331
|
+
....: [0, 1, 0, 1, 0, 0, 0, 0, 0],
|
|
19332
|
+
....: [0, 0, 0, 0,-1, 1, 0, 1, 0],
|
|
19333
|
+
....: [0, 0, 0, 0,-1, 1, 0, 0, 1],
|
|
19334
|
+
....: [0, 0, 0, 0,-1, 0, 1, 1, 0],
|
|
19335
|
+
....: [0, 0, 0, 0,-1, 0, 1, 0, 1]])
|
|
19336
|
+
sage: result, certificate = M.is_totally_unimodular(certificate=True)
|
|
19337
|
+
sage: result, certificate
|
|
19338
|
+
(True, OneSumNode (9×9) with 2 children)
|
|
19339
|
+
sage: unicode_art(certificate)
|
|
19340
|
+
╭───────────OneSumNode (9×9) with 2 children
|
|
19341
|
+
│ │
|
|
19342
|
+
GraphicNode (5×4) CographicNode (4×5)
|
|
19343
|
+
sage: result, certificate = M.is_totally_unimodular(
|
|
19344
|
+
....: certificate=True, stop_when_nonTU=False)
|
|
19345
|
+
sage: result, certificate
|
|
19346
|
+
(True, OneSumNode (9×9) with 2 children)
|
|
19347
|
+
sage: unicode_art(certificate)
|
|
19348
|
+
╭───────────OneSumNode (9×9) with 2 children
|
|
19349
|
+
│ │
|
|
19350
|
+
GraphicNode (5×4) CographicNode (4×5)
|
|
19351
|
+
|
|
19352
|
+
These are tests ``TreeFlagsNorecurse``, ``TreeFlagsStopNoncographic``,
|
|
19353
|
+
and ``TreeFlagsStopNongraphic`` in CMR's ``test_regular.cpp``;
|
|
19354
|
+
the underlying binary linear matroid is regular,
|
|
19355
|
+
but the matrix is not totally unimodular::
|
|
19356
|
+
|
|
19357
|
+
sage: # needs sage.libs.cmr
|
|
19358
|
+
sage: M = matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0],
|
|
19359
|
+
....: [1, 1, 1, 0, 0, 0, 0, 0, 0],
|
|
19360
|
+
....: [1, 0, 0, 1, 0, 0, 0, 0, 0],
|
|
19361
|
+
....: [0, 1, 1, 1, 0, 0, 0, 0, 0],
|
|
19362
|
+
....: [0, 0, 1, 1, 0, 0, 0, 0, 0],
|
|
19363
|
+
....: [0, 0, 0, 0, 1, 1, 1, 0, 0],
|
|
19364
|
+
....: [0, 0, 0, 0, 1, 1, 0, 1, 0],
|
|
19365
|
+
....: [0, 0, 0, 0, 0, 1, 0, 1, 1],
|
|
19366
|
+
....: [0, 0, 0, 0, 0, 0, 1, 1, 1]])
|
|
19367
|
+
sage: result, certificate = M.is_totally_unimodular(certificate=True)
|
|
19368
|
+
sage: result, certificate
|
|
19369
|
+
(False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0))))
|
|
19370
|
+
sage: unicode_art(certificate[0])
|
|
19371
|
+
╭OneSumNode (9×9) with 2 children─╮
|
|
19372
|
+
│ │
|
|
19373
|
+
ThreeConnectedIrregularNode (5×4) UnknownNode (4×5)
|
|
19374
|
+
sage: result, certificate = M.is_totally_unimodular(
|
|
19375
|
+
....: certificate=True,
|
|
19376
|
+
....: stop_when_nonTU=False)
|
|
19377
|
+
sage: result, certificate
|
|
19378
|
+
(False, (OneSumNode (9×9) with 2 children, ((3, 2, 0), (3, 1, 0))))
|
|
19379
|
+
sage: unicode_art(certificate[0])
|
|
19380
|
+
╭OneSumNode (9×9) with 2 children─╮
|
|
19381
|
+
│ │
|
|
19382
|
+
ThreeConnectedIrregularNode (5×4) ThreeConnectedIrregularNode (4×5)
|
|
19383
|
+
"""
|
|
19384
|
+
return self._matrix_cmr().is_totally_unimodular(*args, **kwds)
|
|
19385
|
+
|
|
18192
19386
|
def LLL_gram(self, flag=0):
|
|
18193
19387
|
"""
|
|
18194
19388
|
Return the LLL transformation matrix for this Gram matrix.
|
|
@@ -18350,6 +19544,10 @@ cdef class Matrix(Matrix1):
|
|
|
18350
19544
|
r"""
|
|
18351
19545
|
Return the conjugate-transpose (Hermitian) matrix.
|
|
18352
19546
|
|
|
19547
|
+
.. SEEALSO::
|
|
19548
|
+
|
|
19549
|
+
:meth:`conjugate_transpose`
|
|
19550
|
+
|
|
18353
19551
|
EXAMPLES::
|
|
18354
19552
|
|
|
18355
19553
|
sage: A = matrix(QQbar, [[ -3, 5 - 3*I, 7 - 4*I], # needs sage.rings.number_field
|
|
@@ -18360,7 +19558,7 @@ cdef class Matrix(Matrix1):
|
|
|
18360
19558
|
[ 5 + 3*I -1 - 6*I -3 - 6*I]
|
|
18361
19559
|
[ 7 + 4*I 3 - 5*I 5 - 1*I]
|
|
18362
19560
|
"""
|
|
18363
|
-
return self.
|
|
19561
|
+
return self.conjugate_transpose()
|
|
18364
19562
|
|
|
18365
19563
|
|
|
18366
19564
|
def _smith_diag(d, transformation=True):
|